1use super::{
6 error::SyscallError, exec::sys_execve, fork::sys_fork, numbers::*, process as proc_sys,
7 SyscallFrame,
8};
9use crate::{
10 arch::x86_64::pci,
11 capability::{get_capability_manager, CapId, CapPermissions, ResourceType},
12 hardware::storage::{
13 ahci,
14 virtio_block::{self, BlockDevice, SECTOR_SIZE},
15 },
16 ipc::{
17 channel::{self, ChanId},
18 message::IpcMessage,
19 port::{self, PortId},
20 reply,
21 semaphore::{self, SemId},
22 shared_ring::{self, RingId},
23 },
24 memory::{UserSliceRead, UserSliceWrite},
25 process::current_task_clone,
26 silo,
27};
28use alloc::{sync::Arc, vec};
29use core::sync::atomic::{AtomicU32, Ordering};
30
31static NET_SEND_ERR_LOG_BUDGET: AtomicU32 = AtomicU32::new(32);
32static NET_RECV_ERR_LOG_BUDGET: AtomicU32 = AtomicU32::new(32);
33static DHCP_TRACE_LOG_BUDGET: AtomicU32 = AtomicU32::new(64);
34
35fn trace_dhcp_frame(tag: &str, frame: &[u8]) {
37 if DHCP_TRACE_LOG_BUDGET.fetch_sub(1, Ordering::Relaxed) == 0 {
38 return;
39 }
40 if frame.len() < 14 {
41 return;
42 }
43 let ethertype = u16::from_be_bytes([frame[12], frame[13]]);
44 if ethertype != 0x0800 {
45 return;
46 }
47 if frame.len() < 34 {
48 return;
49 }
50 let ip_hlen = ((frame[14] & 0x0f) as usize) * 4;
51 if ip_hlen < 20 || frame.len() < 14 + ip_hlen + 8 {
52 return;
53 }
54 if frame[23] != 17 {
55 return;
56 }
57 let udp = 14 + ip_hlen;
58 let src_port = u16::from_be_bytes([frame[udp], frame[udp + 1]]);
59 let dst_port = u16::from_be_bytes([frame[udp + 2], frame[udp + 3]]);
60 let is_dhcp = (src_port == 68 && dst_port == 67) || (src_port == 67 && dst_port == 68);
61 if !is_dhcp {
62 return;
63 }
64 let mut xid: u32 = 0;
65 let bootp = udp + 8;
66 if frame.len() >= bootp + 8 {
67 xid = u32::from_be_bytes([
68 frame[bootp + 4],
69 frame[bootp + 5],
70 frame[bootp + 6],
71 frame[bootp + 7],
72 ]);
73 }
74 crate::serial_println!(
75 "[dhcp-trace] {} src_port={} dst_port={} len={} xid=0x{:08x}",
76 tag,
77 src_port,
78 dst_port,
79 frame.len(),
80 xid
81 );
82}
83
84#[no_mangle]
96pub extern "C" fn __strat9_syscall_dispatch(frame: &mut SyscallFrame) -> u64 {
97 let syscall_num = frame.rax as usize;
98 let arg1 = frame.rdi;
99 let arg2 = frame.rsi;
100 let arg3 = frame.rdx;
101 let arg4 = frame.r10;
102 let _arg5 = frame.r8;
103 let _arg6 = frame.r9;
104
105 if let Some(tid) = crate::process::current_task_id() {
107 crate::serial_force_println!(
108 "\x1b[32m[syscall] ENTER\x1b[0m: tid={} num={} arg1={:#x} arg2={:#x} rip={:#x}",
109 tid,
110 syscall_num,
111 arg1,
112 arg2,
113 frame.rcx );
115 }
116
117 let result = match syscall_num {
118 SYS_NULL => sys_null(),
119 SYS_HANDLE_DUPLICATE => sys_handle_duplicate(arg1),
120 SYS_HANDLE_CLOSE => sys_handle_close(arg1),
121 SYS_HANDLE_WAIT => sys_handle_wait(arg1, arg2),
122 SYS_HANDLE_GRANT => sys_handle_grant(arg1, arg2),
123 SYS_HANDLE_REVOKE => sys_handle_revoke(arg1),
124 SYS_HANDLE_INFO => sys_handle_info(arg1, arg2),
125
126 SYS_MMAP => super::mmap::sys_mmap(arg1, arg2, arg3 as u32, arg4 as u32, frame.r8, frame.r9),
128 SYS_MUNMAP => super::mmap::sys_munmap(arg1, arg2),
129 SYS_BRK => super::mmap::sys_brk(arg1),
130 SYS_MREMAP => super::mmap::sys_mremap(arg1, arg2, arg3, arg4),
131 SYS_MPROTECT => super::mmap::sys_mprotect(arg1, arg2, arg3),
132
133 SYS_PROC_EXIT => sys_proc_exit(arg1),
134 SYS_PROC_YIELD => sys_proc_yield(),
135 SYS_PROC_FORK => sys_fork(frame).map(|result| result.child_pid as u64),
136 SYS_PROC_GETPID | SYS_GETPID => proc_sys::sys_getpid(),
137 SYS_PROC_GETPPID => proc_sys::sys_getppid(),
138 SYS_GETTID => proc_sys::sys_gettid(),
139 SYS_PROC_WAITPID => {
140 super::wait::sys_waitpid(arg1 as i64, arg2, arg3 as u32).map(|pid| pid as u64)
141 }
142 SYS_PROC_WAIT => super::wait::sys_wait(arg1),
143 SYS_PROC_EXECVE => sys_execve(frame, arg1, arg2, arg3),
144 SYS_FCNTL => super::fcntl::sys_fcntl(arg1, arg2, arg3),
145 SYS_SETPGID => proc_sys::sys_setpgid(arg1 as i64, arg2 as i64),
146 SYS_GETPGID => proc_sys::sys_getpgid(arg1 as i64),
147 SYS_SETSID => proc_sys::sys_setsid(),
148 SYS_GETPGRP => proc_sys::sys_getpgrp(),
149 SYS_GETSID => proc_sys::sys_getsid(arg1 as i64),
150 SYS_GETUID => proc_sys::sys_getuid(),
152 SYS_GETEUID => proc_sys::sys_geteuid(),
153 SYS_GETGID => proc_sys::sys_getgid(),
154 SYS_GETEGID => proc_sys::sys_getegid(),
155 SYS_SETUID => proc_sys::sys_setuid(arg1),
156 SYS_SETGID => proc_sys::sys_setgid(arg1),
157 SYS_THREAD_CREATE => proc_sys::sys_thread_create(frame, arg1, arg2, arg3, arg4, frame.r8),
158 SYS_THREAD_JOIN => proc_sys::sys_thread_join(arg1, arg2, arg3),
159 SYS_THREAD_EXIT => proc_sys::sys_thread_exit(arg1),
160 SYS_UNAME => sys_uname(arg1),
161 SYS_SET_TID_ADDRESS => proc_sys::sys_set_tid_address(arg1),
163 SYS_EXIT_GROUP => proc_sys::sys_exit_group(arg1),
164 SYS_ARCH_PRCTL => proc_sys::sys_arch_prctl(arg1, arg2),
166 SYS_TGKILL => proc_sys::sys_tgkill(arg1, arg2, arg3),
168 SYS_RT_SIGRETURN => super::signal::sys_rt_sigreturn(frame),
169 SYS_FUTEX_WAIT => super::futex::sys_futex_wait(arg1, arg2 as u32, arg3),
170 SYS_FUTEX_WAKE => super::futex::sys_futex_wake(arg1, arg2 as u32),
171 SYS_FUTEX_REQUEUE => super::futex::sys_futex_requeue(arg1, arg2 as u32, arg3 as u32, arg4),
172 SYS_FUTEX_CMP_REQUEUE => super::futex::sys_futex_cmp_requeue(
173 arg1,
174 arg2 as u32,
175 arg3 as u32,
176 arg4,
177 frame.r8 as u32,
178 ),
179 SYS_FUTEX_WAKE_OP => {
180 super::futex::sys_futex_wake_op(arg1, arg2 as u32, arg3 as u32, arg4, frame.r8 as u32)
181 }
182 SYS_KILL => super::signal::sys_kill(arg1 as i64, arg2 as u32),
183 SYS_SIGPROCMASK => sys_sigprocmask(arg1 as i32, arg2, arg3),
184 SYS_SIGACTION => super::signal::sys_sigaction(arg1, arg2, arg3),
185 SYS_SIGALTSTACK => super::signal::sys_sigaltstack(arg1, arg2),
186 SYS_SIGPENDING => super::signal::sys_sigpending(arg1),
187 SYS_SIGSUSPEND => super::signal::sys_sigsuspend(arg1),
188 SYS_SIGTIMEDWAIT => super::signal::sys_sigtimedwait(arg1, arg2, arg3),
189 SYS_SIGQUEUE => super::signal::sys_sigqueue(arg1 as i64, arg2 as u32, arg3),
190 SYS_KILLPG => super::signal::sys_killpg(arg1, arg2 as u32),
191 SYS_GETITIMER => super::signal::sys_getitimer(arg1 as u32, arg2),
192 SYS_SETITIMER => super::signal::sys_setitimer(arg1 as u32, arg2, arg3),
193 SYS_IPC_CREATE_PORT => sys_ipc_create_port(arg1),
194 SYS_IPC_SEND => sys_ipc_send(arg1, arg2),
195 SYS_IPC_RECV => sys_ipc_recv(arg1, arg2),
196 SYS_IPC_TRY_RECV => sys_ipc_try_recv(arg1, arg2),
197 SYS_IPC_CONNECT => sys_ipc_connect(arg1, arg2),
198 SYS_IPC_CALL => sys_ipc_call(arg1, arg2),
199 SYS_IPC_REPLY => sys_ipc_reply(arg1),
200 SYS_IPC_BIND_PORT => sys_ipc_bind_port(arg1, arg2, arg3),
201 SYS_IPC_UNBIND_PORT => sys_ipc_unbind_port(arg1, arg2),
202 SYS_IPC_RING_CREATE => sys_ipc_ring_create(arg1),
203 SYS_IPC_RING_MAP => sys_ipc_ring_map(arg1, arg2),
204 SYS_SEM_CREATE => sys_sem_create(arg1),
205 SYS_SEM_WAIT => sys_sem_wait(arg1),
206 SYS_SEM_TRYWAIT => sys_sem_trywait(arg1),
207 SYS_SEM_POST => sys_sem_post(arg1),
208 SYS_SEM_CLOSE => sys_sem_close(arg1),
209 SYS_PCI_ENUM => sys_pci_enum(arg1, arg2, arg3),
210 SYS_PCI_CFG_READ => sys_pci_cfg_read(arg1, arg2, arg3),
211 SYS_PCI_CFG_WRITE => sys_pci_cfg_write(arg1, arg2, arg3, arg4),
212
213 SYS_CHAN_CREATE => sys_chan_create(arg1),
215 SYS_CHAN_SEND => sys_chan_send(arg1, arg2),
216 SYS_CHAN_RECV => sys_chan_recv(arg1, arg2),
217 SYS_CHAN_TRY_RECV => sys_chan_try_recv(arg1, arg2),
218 SYS_CHAN_CLOSE => sys_chan_close(arg1),
219 SYS_MODULE_LOAD => silo::sys_module_load(arg1, arg2),
220 SYS_MODULE_UNLOAD => silo::sys_module_unload(arg1),
221 SYS_MODULE_GET_SYMBOL => silo::sys_module_get_symbol(arg1, arg2),
222 SYS_MODULE_QUERY => silo::sys_module_query(arg1, arg2),
223 SYS_OPEN => sys_open(arg1, arg2, arg3),
224 SYS_WRITE => sys_write(arg1, arg2, arg3),
225 SYS_READ => sys_read(arg1, arg2, arg3),
226 SYS_CLOSE => sys_close(arg1),
227 SYS_LSEEK => sys_lseek(arg1, arg2, arg3),
228 SYS_FSTAT => sys_fstat(arg1, arg2),
229 SYS_STAT => sys_stat(arg1, arg2, arg3),
230 SYS_GETDENTS => sys_getdents(arg1, arg2, arg3),
231 SYS_PIPE => sys_pipe(arg1),
232 SYS_DUP => sys_dup(arg1),
233 SYS_DUP2 => sys_dup2(arg1, arg2),
234 SYS_CHDIR => crate::vfs::sys_chdir(arg1, arg2),
236 SYS_FCHDIR => crate::vfs::sys_fchdir(arg1 as u32),
237 SYS_GETCWD => crate::vfs::sys_getcwd(arg1, arg2),
238 SYS_IOCTL => crate::vfs::sys_ioctl(arg1 as u32, arg2, arg3),
239 SYS_UMASK => crate::vfs::sys_umask(arg1),
240 SYS_UNLINK => crate::vfs::sys_unlink(arg1, arg2),
241 SYS_RMDIR => crate::vfs::sys_rmdir(arg1, arg2),
242 SYS_MKDIR => crate::vfs::sys_mkdir(arg1, arg2, arg3),
243 SYS_RENAME => crate::vfs::sys_rename(arg1, arg2, arg3, arg4),
244 SYS_LINK => crate::vfs::sys_link(arg1, arg2, arg3, arg4),
245 SYS_SYMLINK => crate::vfs::sys_symlink(arg1, arg2, arg3, arg4),
246 SYS_READLINK => crate::vfs::sys_readlink(arg1, arg2, arg3, arg4),
247 SYS_CHMOD => crate::vfs::sys_chmod(arg1, arg2, arg3),
248 SYS_FCHMOD => crate::vfs::sys_fchmod(arg1 as u32, arg2),
249 SYS_TRUNCATE => crate::vfs::sys_truncate(arg1, arg2, arg3),
250 SYS_FTRUNCATE => crate::vfs::sys_ftruncate(arg1 as u32, arg2),
251 SYS_PREAD => crate::vfs::sys_pread(arg1 as u32, arg2, arg3, arg4),
252 SYS_PWRITE => crate::vfs::sys_pwrite(arg1 as u32, arg2, arg3, arg4),
253 SYS_POLL => super::poll::sys_poll(arg1, arg2, arg3),
254 SYS_PPOLL => super::poll::sys_poll(arg1, arg2, 0),
255
256 SYS_NET_RECV => sys_net_recv(arg1, arg2),
258 SYS_NET_SEND => sys_net_send(arg1, arg2),
259 SYS_NET_INFO => sys_net_info(arg1, arg2),
260
261 SYS_VOLUME_READ => sys_volume_read(arg1, arg2, arg3, arg4),
262 SYS_VOLUME_WRITE => sys_volume_write(arg1, arg2, arg3, arg4),
263 SYS_VOLUME_INFO => sys_volume_info(arg1),
264 SYS_CLOCK_GETTIME => super::time::sys_clock_gettime(arg1 as u32, arg2),
265 SYS_NANOSLEEP => super::time::sys_nanosleep(arg1, arg2),
266 SYS_DEBUG_LOG => sys_debug_log(arg1, arg2),
267 SYS_SILO_CREATE => silo::sys_silo_create(arg1),
268 SYS_SILO_CONFIG => silo::sys_silo_config(arg1, arg2),
269 SYS_SILO_ATTACH_MODULE => silo::sys_silo_attach_module(arg1, arg2),
270 SYS_SILO_START => silo::sys_silo_start(arg1),
271 SYS_SILO_STOP => silo::sys_silo_stop(arg1),
272 SYS_SILO_KILL => silo::sys_silo_kill(arg1),
273 SYS_SILO_EVENT_NEXT => silo::sys_silo_event_next(arg1),
274 SYS_SILO_SUSPEND => silo::sys_silo_suspend(arg1),
275 SYS_SILO_RESUME => silo::sys_silo_resume(arg1),
276 SYS_SILO_PLEDGE => silo::sys_silo_pledge(arg1),
277 SYS_SILO_UNVEIL => silo::sys_silo_unveil(arg1, arg2, arg3),
278 SYS_SILO_ENTER_SANDBOX => silo::sys_silo_enter_sandbox(),
279 SYS_ABI_VERSION => {
280 Ok(((strat9_abi::ABI_VERSION_MAJOR as u64) << 16)
281 | (strat9_abi::ABI_VERSION_MINOR as u64))
282 }
283 _ => {
284 log::warn!("Unknown syscall: {} (0x{:x})", syscall_num, syscall_num);
285 Err(SyscallError::NotImplemented)
286 }
287 };
288
289 match result {
290 Ok(val) => {
291 if syscall_num == SYS_PROC_FORK {
292 crate::serial_println!("[syscall] FORK returning Ok({})", val);
293 }
294 frame.rax = val;
295 }
296 Err(e) => {
297 if syscall_num == SYS_PROC_FORK {
298 crate::serial_println!("[syscall] FORK returning err");
299 }
300 frame.rax = e.to_raw();
301 }
302 }
303
304 crate::process::signal::deliver_pending_signal(frame);
305
306 frame.rax
307}
308
309#[no_mangle]
312pub extern "C" fn dispatch(frame: &mut SyscallFrame) -> u64 {
313 __strat9_syscall_dispatch(frame)
314}
315
316fn sys_null() -> Result<u64, SyscallError> {
322 Ok(0x57A79)
323}
324
325fn sys_handle_close(_handle: u64) -> Result<u64, SyscallError> {
327 crate::silo::enforce_cap_for_current_task(_handle)?;
328 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
329 let caps = unsafe { &mut *task.process.capabilities.get() };
330 if let Some(cap) = caps.remove(CapId::from_raw(_handle)) {
331 cleanup_cap_resource(&cap);
332 log::trace!("syscall: HANDLE_CLOSE({})", _handle);
333 Ok(0)
334 } else {
335 Err(SyscallError::BadHandle)
336 }
337}
338
339fn cleanup_cap_resource(cap: &crate::capability::Capability) {
341 match cap.resource_type {
342 ResourceType::File => {
343 if let Ok(fd) = u32::try_from(cap.resource) {
344 let _ = crate::vfs::close(fd);
345 }
346 }
347 ResourceType::SharedRing => {
348 let _ = shared_ring::destroy_ring(RingId::from_u64(cap.resource as u64));
349 }
350 ResourceType::Semaphore => {
351 let _ = semaphore::destroy_semaphore(SemId::from_u64(cap.resource as u64));
352 }
353 _ => {}
354 }
355}
356
357fn sys_handle_duplicate(handle: u64) -> Result<u64, SyscallError> {
359 crate::silo::enforce_cap_for_current_task(handle)?;
360 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
361 let caps = unsafe { &mut *task.process.capabilities.get() };
362 let dup = caps
363 .duplicate(CapId::from_raw(handle))
364 .ok_or(SyscallError::PermissionDenied)?;
365 let id = caps.insert(dup);
366 Ok(id.as_u64())
367}
368
369const HANDLE_EVENT_READABLE: u64 = 1 << 0;
370const HANDLE_EVENT_WRITABLE: u64 = 1 << 1;
371
372fn poll_handle_events(handle: u64) -> Result<u64, SyscallError> {
374 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
375 let caps = unsafe { &*task.process.capabilities.get() };
376 let cap = caps
377 .get(CapId::from_raw(handle))
378 .ok_or(SyscallError::BadHandle)?;
379
380 match cap.resource_type {
381 ResourceType::Semaphore => {
382 if !cap.permissions.read {
383 return Err(SyscallError::PermissionDenied);
384 }
385 let sem = semaphore::get_semaphore(SemId::from_u64(cap.resource as u64))
386 .ok_or(SyscallError::BadHandle)?;
387 if sem.is_destroyed() {
388 return Err(SyscallError::Pipe);
389 }
390 if sem.count() > 0 {
391 Ok(HANDLE_EVENT_READABLE)
392 } else {
393 Ok(0)
394 }
395 }
396 ResourceType::IpcPort => {
397 let port = port::get_port(PortId::from_u64(cap.resource as u64))
398 .ok_or(SyscallError::BadHandle)?;
399 if port.is_destroyed() {
400 return Err(SyscallError::Pipe);
401 }
402 let mut events = 0u64;
403 if cap.permissions.read && port.has_messages() {
404 events |= HANDLE_EVENT_READABLE;
405 }
406 if cap.permissions.write && port.can_send() {
407 events |= HANDLE_EVENT_WRITABLE;
408 }
409 if events == 0 && !cap.permissions.read && !cap.permissions.write {
410 return Err(SyscallError::PermissionDenied);
411 }
412 Ok(events)
413 }
414 ResourceType::Channel => {
415 let chan = channel::get_channel(ChanId::from_u64(cap.resource as u64))
416 .ok_or(SyscallError::BadHandle)?;
417 if chan.is_destroyed() {
418 return Err(SyscallError::Pipe);
419 }
420 let mut events = 0u64;
421 if cap.permissions.read && !chan.is_empty() {
422 events |= HANDLE_EVENT_READABLE;
423 }
424 if cap.permissions.write && chan.can_send() {
425 events |= HANDLE_EVENT_WRITABLE;
426 }
427 if events == 0 && !cap.permissions.read && !cap.permissions.write {
428 return Err(SyscallError::PermissionDenied);
429 }
430 Ok(events)
431 }
432 ResourceType::SharedRing => {
433 let _ = shared_ring::get_ring(RingId::from_u64(cap.resource as u64))
434 .ok_or(SyscallError::BadHandle)?;
435 let mut events = 0u64;
436 if cap.permissions.read {
437 events |= HANDLE_EVENT_READABLE;
438 }
439 if cap.permissions.write {
440 events |= HANDLE_EVENT_WRITABLE;
441 }
442 if events == 0 {
443 return Err(SyscallError::PermissionDenied);
444 }
445 Ok(events)
446 }
447 _ => Err(SyscallError::NotSupported),
448 }
449}
450
451fn sys_handle_wait(handle: u64, timeout_ns: u64) -> Result<u64, SyscallError> {
453 crate::silo::enforce_cap_for_current_task(handle)?;
454
455 let check_ready = || -> Result<u64, SyscallError> {
456 let events = poll_handle_events(handle)?;
457 if events != 0 {
458 Ok(events)
459 } else {
460 Err(SyscallError::Again)
461 }
462 };
463
464 if timeout_ns == 0 {
465 return check_ready();
466 }
467
468 let deadline = if timeout_ns == u64::MAX {
469 None
470 } else {
471 Some(crate::syscall::time::current_time_ns().saturating_add(timeout_ns))
472 };
473
474 loop {
475 if let Ok(events) = check_ready() {
476 return Ok(events);
477 }
478
479 if crate::process::has_pending_signals() {
480 return Err(SyscallError::Interrupted);
481 }
482
483 let now = crate::syscall::time::current_time_ns();
484 let wake_ns = if let Some(deadline_ns) = deadline {
485 if now >= deadline_ns {
486 return Err(SyscallError::TimedOut);
487 }
488 core::cmp::min(deadline_ns, now.saturating_add(10_000_000))
489 } else {
490 now.saturating_add(10_000_000)
491 };
492
493 if let Some(task) = current_task_clone() {
494 task.wake_deadline_ns.store(wake_ns, Ordering::Relaxed);
495 }
496 crate::process::block_current_task();
497 if let Some(task) = current_task_clone() {
498 task.wake_deadline_ns.store(0, Ordering::Relaxed);
499 }
500 }
501}
502
503fn sys_handle_grant(handle: u64, target_pid: u64) -> Result<u64, SyscallError> {
505 crate::silo::enforce_cap_for_current_task(handle)?;
506 crate::silo::enforce_silo_may_grant()?;
507 let pid = u32::try_from(target_pid).map_err(|_| SyscallError::InvalidArgument)?;
508
509 let source = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
510 let granted = {
511 let source_caps = unsafe { &*source.process.capabilities.get() };
512 let cap = source_caps
513 .get(CapId::from_raw(handle))
514 .ok_or(SyscallError::BadHandle)?;
515 if !cap.permissions.grant {
516 return Err(SyscallError::PermissionDenied);
517 }
518 let mut dup = cap.clone();
519 dup.id = CapId::new();
520 dup
521 };
522
523 let target = crate::process::get_task_by_pid(pid).ok_or(SyscallError::NotFound)?;
524 let target_caps = unsafe { &mut *target.process.capabilities.get() };
525 let new_id = target_caps.insert(granted);
526 Ok(new_id.as_u64())
527}
528
529fn sys_handle_revoke(handle: u64) -> Result<u64, SyscallError> {
531 crate::silo::enforce_cap_for_current_task(handle)?;
532 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
533 let caps = unsafe { &mut *task.process.capabilities.get() };
534
535 {
536 let cap = caps
537 .get(CapId::from_raw(handle))
538 .ok_or(SyscallError::BadHandle)?;
539 if !cap.permissions.revoke {
540 return Err(SyscallError::PermissionDenied);
541 }
542 }
543
544 let cap = caps
545 .remove(CapId::from_raw(handle))
546 .ok_or(SyscallError::BadHandle)?;
547 cleanup_cap_resource(&cap);
548 Ok(0)
549}
550
551use strat9_abi::data::HandleInfo as HandleInfoAbi;
552
553fn cap_perm_bits(p: CapPermissions) -> u32 {
555 (if p.read { 1 } else { 0 })
556 | (if p.write { 1 << 1 } else { 0 })
557 | (if p.execute { 1 << 2 } else { 0 })
558 | (if p.grant { 1 << 3 } else { 0 })
559 | (if p.revoke { 1 << 4 } else { 0 })
560}
561
562fn resource_type_code(rt: ResourceType) -> u32 {
564 match rt {
565 ResourceType::MemoryRegion => 1,
566 ResourceType::IoPortRange => 2,
567 ResourceType::InterruptLine => 3,
568 ResourceType::IpcPort => 4,
569 ResourceType::Channel => 5,
570 ResourceType::SharedRing => 6,
571 ResourceType::Semaphore => 7,
572 ResourceType::Device => 8,
573 ResourceType::AddressSpace => 9,
574 ResourceType::Silo => 10,
575 ResourceType::Module => 11,
576 ResourceType::File => 12,
577 ResourceType::Nic => 13,
578 ResourceType::FileSystem => 14,
579 ResourceType::Console => 15,
580 ResourceType::Keyboard => 16,
581 ResourceType::Volume => 17,
582 ResourceType::Namespace => 18,
583 }
584}
585
586fn sys_handle_info(handle: u64, out_ptr: u64) -> Result<u64, SyscallError> {
588 crate::silo::enforce_cap_for_current_task(handle)?;
589 if out_ptr == 0 {
590 return Err(SyscallError::Fault);
591 }
592 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
593 let caps = unsafe { &*task.process.capabilities.get() };
594 let cap = caps
595 .get(CapId::from_raw(handle))
596 .ok_or(SyscallError::BadHandle)?;
597
598 let info = HandleInfoAbi {
599 resource_type: resource_type_code(cap.resource_type),
600 permissions: cap_perm_bits(cap.permissions),
601 resource: cap.resource as u64,
602 };
603 let user = UserSliceWrite::new(out_ptr, core::mem::size_of::<HandleInfoAbi>())?;
604 let bytes = unsafe {
605 core::slice::from_raw_parts(
606 &info as *const HandleInfoAbi as *const u8,
607 core::mem::size_of::<HandleInfoAbi>(),
608 )
609 };
610 user.copy_from(bytes);
611 Ok(0)
612}
613
614fn sys_proc_exit(exit_code: u64) -> Result<u64, SyscallError> {
618 log::info!("syscall: PROC_EXIT(code={})", exit_code);
619
620 crate::process::scheduler::exit_current_task(exit_code as i32)
623}
624
625fn sys_proc_yield() -> Result<u64, SyscallError> {
627 crate::process::yield_task();
628 Ok(0)
629}
630
631fn sys_sigprocmask(how: i32, set_ptr: u64, oldset_ptr: u64) -> Result<u64, SyscallError> {
635 use crate::process::current_task_clone;
636
637 const SIG_BLOCK: i32 = 0;
638 const SIG_UNBLOCK: i32 = 1;
639 const SIG_SETMASK: i32 = 2;
640
641 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
642
643 let blocked = &task.blocked_signals;
644
645 if oldset_ptr != 0 {
646 let old_mask = blocked.get_mask();
647 let user = UserSliceWrite::new(oldset_ptr, 8)?;
648 user.copy_from(&old_mask.to_ne_bytes());
649 }
650
651 if set_ptr != 0 {
652 let user = UserSliceRead::new(set_ptr, 8)?;
653 let mut buf = [0u8; 8];
654 user.copy_to(&mut buf);
655 let new_mask = u64::from_ne_bytes(buf);
656
657 let old_mask = blocked.get_mask();
658 let updated_mask = match how {
659 SIG_BLOCK => old_mask | new_mask,
660 SIG_UNBLOCK => old_mask & !new_mask,
661 SIG_SETMASK => new_mask,
662 _ => return Err(SyscallError::InvalidArgument),
663 };
664
665 blocked.set_mask(updated_mask);
666 }
667
668 Ok(0)
669}
670
671fn sys_uname(uts_ptr: u64) -> Result<u64, SyscallError> {
673 const UTS_FIELD_LEN: usize = 65;
674 const UTS_TOTAL_LEN: usize = UTS_FIELD_LEN * 6;
675
676 if uts_ptr == 0 {
677 return Err(SyscallError::Fault);
678 }
679
680 fn write_field(dst: &mut [u8], src: &[u8]) {
682 let n = core::cmp::min(src.len(), dst.len().saturating_sub(1));
683 if n > 0 {
684 dst[..n].copy_from_slice(&src[..n]);
685 }
686 dst[n] = 0;
687 }
688
689 let mut uts = [0u8; UTS_TOTAL_LEN];
690 write_field(&mut uts[0 * UTS_FIELD_LEN..1 * UTS_FIELD_LEN], b"Strat9");
691 write_field(&mut uts[1 * UTS_FIELD_LEN..2 * UTS_FIELD_LEN], b"localhost");
692 write_field(&mut uts[2 * UTS_FIELD_LEN..3 * UTS_FIELD_LEN], b"0.1.0");
693 write_field(&mut uts[3 * UTS_FIELD_LEN..4 * UTS_FIELD_LEN], b"Strat9-OS");
694 write_field(&mut uts[4 * UTS_FIELD_LEN..5 * UTS_FIELD_LEN], b"x86_64");
695 write_field(
696 &mut uts[5 * UTS_FIELD_LEN..6 * UTS_FIELD_LEN],
697 b"localdomain",
698 );
699
700 let user = UserSliceWrite::new(uts_ptr, UTS_TOTAL_LEN)?;
701 user.copy_from(&uts);
702 Ok(0)
703}
704
705fn sys_write(fd: u64, buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
707 crate::vfs::sys_write(fd as u32, buf_ptr, buf_len)
708}
709
710fn sys_open(path_ptr: u64, path_len: u64, flags: u64) -> Result<u64, SyscallError> {
712 crate::vfs::sys_open(path_ptr, path_len, flags)
713}
714
715fn sys_read(fd: u64, buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
717 crate::vfs::sys_read(fd as u32, buf_ptr, buf_len)
718}
719
720fn sys_close(fd: u64) -> Result<u64, SyscallError> {
722 crate::vfs::sys_close(fd as u32)
723}
724
725fn sys_lseek(fd: u64, offset: u64, whence: u64) -> Result<u64, SyscallError> {
727 crate::vfs::sys_lseek(fd as u32, offset as i64, whence as u32)
728}
729
730fn sys_fstat(fd: u64, stat_ptr: u64) -> Result<u64, SyscallError> {
732 crate::vfs::sys_fstat(fd as u32, stat_ptr)
733}
734
735fn sys_stat(path_ptr: u64, path_len: u64, stat_ptr: u64) -> Result<u64, SyscallError> {
737 crate::vfs::sys_stat(path_ptr, path_len, stat_ptr)
738}
739
740fn sys_getdents(fd: u64, buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
742 crate::vfs::sys_getdents(fd as u32, buf_ptr, buf_len)
743}
744
745fn sys_pipe(fds_ptr: u64) -> Result<u64, SyscallError> {
747 crate::vfs::sys_pipe(fds_ptr)
748}
749
750fn sys_dup(old_fd: u64) -> Result<u64, SyscallError> {
752 crate::vfs::sys_dup(old_fd as u32)
753}
754
755fn sys_dup2(old_fd: u64, new_fd: u64) -> Result<u64, SyscallError> {
757 crate::vfs::sys_dup2(old_fd as u32, new_fd as u32)
758}
759
760const MAX_SECTORS_PER_CALL: u64 = 256;
765
766enum VolumeDeviceRef {
767 Virtio(&'static virtio_block::VirtioBlockDevice),
768 Ahci(&'static ahci::AhciController),
769}
770
771impl VolumeDeviceRef {
772 fn sector_count(&self) -> u64 {
774 match self {
775 VolumeDeviceRef::Virtio(dev) => BlockDevice::sector_count(*dev),
776 VolumeDeviceRef::Ahci(dev) => BlockDevice::sector_count(*dev),
777 }
778 }
779
780 fn read_sector(&self, sector: u64, buf: &mut [u8]) -> Result<(), SyscallError> {
782 match self {
783 VolumeDeviceRef::Virtio(dev) => {
784 BlockDevice::read_sector(*dev, sector, buf).map_err(SyscallError::from)
785 }
786 VolumeDeviceRef::Ahci(dev) => {
787 BlockDevice::read_sector(*dev, sector, buf).map_err(SyscallError::from)
788 }
789 }
790 }
791
792 fn write_sector(&self, sector: u64, buf: &[u8]) -> Result<(), SyscallError> {
794 match self {
795 VolumeDeviceRef::Virtio(dev) => {
796 BlockDevice::write_sector(*dev, sector, buf).map_err(SyscallError::from)
797 }
798 VolumeDeviceRef::Ahci(dev) => {
799 BlockDevice::write_sector(*dev, sector, buf).map_err(SyscallError::from)
800 }
801 }
802 }
803}
804
805fn resolve_volume_device(
807 handle: u64,
808 required: CapPermissions,
809) -> Result<VolumeDeviceRef, SyscallError> {
810 crate::silo::enforce_cap_for_current_task(handle)?;
811 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
812 let caps = unsafe { &*task.process.capabilities.get() };
813 let cap = caps
814 .get_with_permissions(CapId::from_raw(handle), required)
815 .ok_or(SyscallError::PermissionDenied)?;
816 if cap.resource_type != ResourceType::Volume {
817 return Err(SyscallError::BadHandle);
818 }
819
820 if let Some(device) = virtio_block::get_device() {
821 let device_ptr = device as *const virtio_block::VirtioBlockDevice as usize;
822 if cap.resource == device_ptr {
823 return Ok(VolumeDeviceRef::Virtio(device));
824 }
825 }
826 if let Some(device) = ahci::get_device() {
827 let device_ptr = device as *const ahci::AhciController as usize;
828 if cap.resource == device_ptr {
829 return Ok(VolumeDeviceRef::Ahci(device));
830 }
831 }
832 Err(SyscallError::BadHandle)
833}
834
835fn sys_volume_read(
837 handle: u64,
838 sector: u64,
839 buf_ptr: u64,
840 sector_count: u64,
841) -> Result<u64, SyscallError> {
842 if sector_count == 0 {
843 return Ok(0);
844 }
845 if sector_count > MAX_SECTORS_PER_CALL {
846 return Err(SyscallError::InvalidArgument);
847 }
848
849 let required = CapPermissions {
850 read: true,
851 write: false,
852 execute: false,
853 grant: false,
854 revoke: false,
855 };
856 let device = resolve_volume_device(handle, required)?;
857 let total_sectors = device.sector_count();
858 if sector >= total_sectors || sector.saturating_add(sector_count) > total_sectors {
859 return Err(SyscallError::InvalidArgument);
860 }
861
862 let mut kbuf = [0u8; SECTOR_SIZE];
863 for i in 0..sector_count {
864 let cur_sector = sector.checked_add(i).ok_or(SyscallError::InvalidArgument)?;
865 device.read_sector(cur_sector, &mut kbuf)?;
866 let offset = (i as usize)
867 .checked_mul(SECTOR_SIZE)
868 .ok_or(SyscallError::InvalidArgument)?;
869 let ptr = buf_ptr
870 .checked_add(offset as u64)
871 .ok_or(SyscallError::Fault)?;
872 let user = UserSliceWrite::new(ptr, SECTOR_SIZE)?;
873 user.copy_from(&kbuf);
874 }
875
876 Ok(sector_count)
877}
878
879fn sys_volume_write(
881 handle: u64,
882 sector: u64,
883 buf_ptr: u64,
884 sector_count: u64,
885) -> Result<u64, SyscallError> {
886 if sector_count == 0 {
887 return Ok(0);
888 }
889 if sector_count > MAX_SECTORS_PER_CALL {
890 return Err(SyscallError::InvalidArgument);
891 }
892
893 let required = CapPermissions {
894 read: false,
895 write: true,
896 execute: false,
897 grant: false,
898 revoke: false,
899 };
900 let device = resolve_volume_device(handle, required)?;
901 let total_sectors = device.sector_count();
902 if sector >= total_sectors || sector.saturating_add(sector_count) > total_sectors {
903 return Err(SyscallError::InvalidArgument);
904 }
905
906 let mut kbuf = [0u8; SECTOR_SIZE];
907 for i in 0..sector_count {
908 let cur_sector = sector.checked_add(i).ok_or(SyscallError::InvalidArgument)?;
909 let offset = (i as usize)
910 .checked_mul(SECTOR_SIZE)
911 .ok_or(SyscallError::InvalidArgument)?;
912 let ptr = buf_ptr
913 .checked_add(offset as u64)
914 .ok_or(SyscallError::Fault)?;
915 let user = UserSliceRead::new(ptr, SECTOR_SIZE)?;
916 let data = user.read_to_vec();
917 if data.len() != SECTOR_SIZE {
918 return Err(SyscallError::InvalidArgument);
919 }
920 kbuf.copy_from_slice(&data);
921 device.write_sector(cur_sector, &kbuf)?;
922 }
923
924 Ok(sector_count)
925}
926
927fn sys_volume_info(handle: u64) -> Result<u64, SyscallError> {
929 let required = CapPermissions {
930 read: true,
931 write: false,
932 execute: false,
933 grant: false,
934 revoke: false,
935 };
936 let device = resolve_volume_device(handle, required)?;
937 Ok(device.sector_count())
938}
939
940fn sys_debug_log(buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
944 if buf_len == 0 {
945 return Ok(0);
946 }
947
948 crate::silo::enforce_console_access()?;
950
951 let len = core::cmp::min(buf_len as usize, 4096);
952
953 let user_buf = UserSliceRead::new(buf_ptr, len)?;
955
956 let mut kbuf = [0u8; 4096];
958 let copied = user_buf.copy_to(&mut kbuf);
959
960 crate::serial_print!("[user-debug] ");
962 for &byte in &kbuf[..copied] {
963 crate::serial_print!("{}", byte as char);
964 }
965 crate::serial_println!();
966
967 if let Some(task) = crate::process::current_task_clone() {
968 if let Some(silo_id) = crate::silo::task_silo_id(task.id) {
969 crate::silo::silo_output_write(silo_id, &kbuf[..copied]);
970 }
971 }
972
973 Ok(copied as u64)
974}
975
976pub fn sys_net_recv(buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
982 let device = crate::hardware::nic::get_default_device().ok_or(SyscallError::Again)?;
983 let mut kbuf = vec![0u8; buf_len as usize];
984
985 let n = match device.receive(&mut kbuf) {
986 Ok(n) => n,
987 Err(e) => {
988 let se = SyscallError::from(e);
989 if se != SyscallError::Again
990 && NET_RECV_ERR_LOG_BUDGET.fetch_sub(1, Ordering::Relaxed) > 0
991 {
992 crate::serial_println!("[net-sys] recv error: {:?} -> {}", e, se.name());
993 }
994 return Err(se);
995 }
996 };
997 trace_dhcp_frame("rx", &kbuf[..n]);
998
999 let user = UserSliceWrite::new(buf_ptr, n)?;
1000 user.copy_from(&kbuf[..n]);
1001 Ok(n as u64)
1002}
1003
1004pub fn sys_net_send(buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
1006 let device = crate::hardware::nic::get_default_device().ok_or(SyscallError::Again)?;
1007 let user = UserSliceRead::new(buf_ptr, buf_len as usize)?;
1008 let kbuf = user.read_to_vec();
1009 trace_dhcp_frame("tx", &kbuf);
1010
1011 if let Err(e) = device.transmit(&kbuf) {
1012 let se = SyscallError::from(e);
1013 if NET_SEND_ERR_LOG_BUDGET.fetch_sub(1, Ordering::Relaxed) > 0 {
1014 crate::serial_println!("[net-sys] send error: {:?} -> {}", e, se.name());
1015 }
1016 return Err(se);
1017 }
1018
1019 Ok(buf_len)
1020}
1021
1022pub fn sys_net_info(info_type: u64, buf_ptr: u64) -> Result<u64, SyscallError> {
1024 let device = crate::hardware::nic::get_default_device().ok_or(SyscallError::Again)?;
1025
1026 match info_type {
1027 0 => {
1028 let mac = device.mac_address();
1029 let user = UserSliceWrite::new(buf_ptr, 6)?;
1030 user.copy_from(&mac);
1031 Ok(6)
1032 }
1033 _ => Err(SyscallError::InvalidArgument),
1034 }
1035}
1036
1037fn sys_ipc_create_port(_flags: u64) -> Result<u64, SyscallError> {
1043 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1044 let port_id = port::create_port(task.id);
1045 let cap = get_capability_manager().create_capability(
1046 ResourceType::IpcPort,
1047 port_id.as_u64() as usize,
1048 CapPermissions::all(),
1049 );
1050 let cap_id = unsafe { (&mut *task.process.capabilities.get()).insert(cap) };
1051 Ok(cap_id.as_u64())
1052}
1053
1054fn sys_ipc_send(port: u64, _msg_ptr: u64) -> Result<u64, SyscallError> {
1056 crate::silo::enforce_cap_for_current_task(port)?;
1057 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1058 let caps = unsafe { &*task.process.capabilities.get() };
1059 let required = CapPermissions {
1060 read: false,
1061 write: true,
1062 execute: false,
1063 grant: false,
1064 revoke: false,
1065 };
1066 let cap = caps
1067 .get_with_permissions(CapId::from_raw(port), required)
1068 .ok_or(SyscallError::PermissionDenied)?;
1069 if cap.resource_type != ResourceType::IpcPort {
1070 return Err(SyscallError::BadHandle);
1071 }
1072
1073 const MSG_SIZE: usize = core::mem::size_of::<IpcMessage>();
1074 let user = UserSliceRead::new(_msg_ptr, MSG_SIZE)?;
1075 let mut buf = [0u8; MSG_SIZE];
1076 user.copy_to(&mut buf);
1077 let mut msg = crate::ipc::message::ipc_message_from_raw(&buf);
1078
1079 msg.sender = task.id.as_u64();
1081
1082 if msg.flags == 0 {
1083 if let Some((sid, _label, _mem_used, _mem_min, _mem_max)) =
1084 crate::silo::silo_info_for_task(task.id)
1085 {
1086 if let Some(snapshot) = crate::silo::list_silos_snapshot()
1087 .into_iter()
1088 .find(|s| s.id == sid)
1089 {
1090 let structured_label = crate::ipc::message::IpcLabel {
1091 tier: snapshot.tier as u8,
1092 family: 5,
1093 compartment: sid as u16,
1094 };
1095 msg.flags = unsafe { core::mem::transmute(structured_label) };
1096 }
1097 }
1098 }
1099
1100 let port_id = PortId::from_u64(cap.resource as u64);
1101 let port = port::get_port(port_id).ok_or(SyscallError::BadHandle)?;
1102 port.send(msg).map_err(SyscallError::from)?;
1103 Ok(0)
1104}
1105
1106fn sys_ipc_recv(port: u64, _msg_ptr: u64) -> Result<u64, SyscallError> {
1108 crate::silo::enforce_cap_for_current_task(port)?;
1109 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1110 let caps = unsafe { &*task.process.capabilities.get() };
1111 let required = CapPermissions {
1112 read: true,
1113 write: false,
1114 execute: false,
1115 grant: false,
1116 revoke: false,
1117 };
1118 let cap = caps
1119 .get_with_permissions(CapId::from_raw(port), required)
1120 .ok_or(SyscallError::PermissionDenied)?;
1121 if cap.resource_type != ResourceType::IpcPort {
1122 return Err(SyscallError::BadHandle);
1123 }
1124
1125 let port_id = PortId::from_u64(cap.resource as u64);
1126 let port = port::get_port(port_id).ok_or(SyscallError::BadHandle)?;
1127 let mut msg = port.recv().map_err(SyscallError::from)?;
1128
1129 if msg.flags != 0 {
1131 let sender_id = crate::process::TaskId::from_u64(msg.sender);
1132 let sender = crate::process::get_task_by_id(sender_id).ok_or(SyscallError::BadHandle)?;
1133 let sender_caps = unsafe { &mut *sender.process.capabilities.get() };
1134 let dup = sender_caps
1135 .duplicate(CapId::from_raw(msg.flags as u64))
1136 .ok_or(SyscallError::PermissionDenied)?;
1137
1138 let receiver = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1139 let receiver_caps = unsafe { &mut *receiver.process.capabilities.get() };
1140 let new_id = receiver_caps.insert(dup);
1141 if new_id.as_u64() > u32::MAX as u64 {
1142 return Err(SyscallError::InvalidArgument);
1143 }
1144 msg.flags = new_id.as_u64() as u32;
1145 }
1146
1147 const MSG_SIZE: usize = core::mem::size_of::<IpcMessage>();
1148 let mut buf = [0u8; MSG_SIZE];
1149 crate::ipc::message::ipc_message_to_raw(&msg, &mut buf);
1150 let user = UserSliceWrite::new(_msg_ptr, MSG_SIZE)?;
1151 user.copy_from(&buf);
1152 Ok(0)
1153}
1154
1155fn sys_ipc_try_recv(port: u64, _msg_ptr: u64) -> Result<u64, SyscallError> {
1157 crate::silo::enforce_cap_for_current_task(port)?;
1158 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1159 let caps = unsafe { &*task.process.capabilities.get() };
1160 let required = CapPermissions {
1161 read: true,
1162 write: false,
1163 execute: false,
1164 grant: false,
1165 revoke: false,
1166 };
1167 let cap = caps
1168 .get_with_permissions(CapId::from_raw(port), required)
1169 .ok_or(SyscallError::PermissionDenied)?;
1170 if cap.resource_type != ResourceType::IpcPort {
1171 return Err(SyscallError::BadHandle);
1172 }
1173
1174 let port_id = PortId::from_u64(cap.resource as u64);
1175 let port = port::get_port(port_id).ok_or(SyscallError::BadHandle)?;
1176 let msg_opt = port.try_recv().map_err(SyscallError::from)?;
1177
1178 let mut msg = match msg_opt {
1179 Some(m) => m,
1180 None => return Err(SyscallError::Again),
1181 };
1182
1183 if msg.flags != 0 {
1185 let sender_id = crate::process::TaskId::from_u64(msg.sender);
1186 let sender = crate::process::get_task_by_id(sender_id).ok_or(SyscallError::BadHandle)?;
1187 let sender_caps = unsafe { &mut *sender.process.capabilities.get() };
1188 let dup = sender_caps
1189 .duplicate(CapId::from_raw(msg.flags as u64))
1190 .ok_or(SyscallError::PermissionDenied)?;
1191
1192 let receiver = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1193 let receiver_caps = unsafe { &mut *receiver.process.capabilities.get() };
1194 let new_id = receiver_caps.insert(dup);
1195 if new_id.as_u64() > u32::MAX as u64 {
1196 return Err(SyscallError::InvalidArgument);
1197 }
1198 msg.flags = new_id.as_u64() as u32;
1199 }
1200
1201 const MSG_SIZE: usize = core::mem::size_of::<IpcMessage>();
1202 let mut buf = [0u8; MSG_SIZE];
1203 crate::ipc::message::ipc_message_to_raw(&msg, &mut buf);
1204 let user = UserSliceWrite::new(_msg_ptr, MSG_SIZE)?;
1205 user.copy_from(&buf);
1206 Ok(0)
1207}
1208
1209fn sys_ipc_connect(path_ptr: u64, path_len: u64) -> Result<u64, SyscallError> {
1211 if path_ptr == 0 || path_len == 0 {
1212 return Err(SyscallError::Fault);
1213 }
1214 const MAX_PATH_LEN: usize = 4096;
1215 if path_len as usize > MAX_PATH_LEN {
1216 return Err(SyscallError::InvalidArgument);
1217 }
1218 let user = UserSliceRead::new(path_ptr, path_len as usize)?;
1219 let bytes = user.read_to_vec();
1220 let path = core::str::from_utf8(&bytes).map_err(SyscallError::from)?;
1221
1222 let (port_raw, _remaining) = crate::namespace::resolve(path).ok_or(SyscallError::NotFound)?;
1223 let port_id = PortId::from_u64(port_raw);
1224 if port::get_port(port_id).is_none() {
1225 return Err(SyscallError::BadHandle);
1226 }
1227
1228 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1229 let cap = get_capability_manager().create_capability(
1230 ResourceType::IpcPort,
1231 port_raw as usize,
1232 CapPermissions {
1233 read: true,
1234 write: true,
1235 execute: false,
1236 grant: false,
1237 revoke: false,
1238 },
1239 );
1240 let cap_id = unsafe { (&mut *task.process.capabilities.get()).insert(cap) };
1241 Ok(cap_id.as_u64())
1242}
1243
1244fn sys_ipc_call(port: u64, _msg_ptr: u64) -> Result<u64, SyscallError> {
1246 crate::silo::enforce_cap_for_current_task(port)?;
1247 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1248 let caps = unsafe { &*task.process.capabilities.get() };
1249 let required = CapPermissions {
1250 read: false,
1251 write: true,
1252 execute: false,
1253 grant: false,
1254 revoke: false,
1255 };
1256 let cap = caps
1257 .get_with_permissions(CapId::from_raw(port), required)
1258 .ok_or(SyscallError::PermissionDenied)?;
1259 if cap.resource_type != ResourceType::IpcPort {
1260 return Err(SyscallError::BadHandle);
1261 }
1262
1263 const MSG_SIZE: usize = core::mem::size_of::<IpcMessage>();
1264 let user = UserSliceRead::new(_msg_ptr, MSG_SIZE)?;
1265 let mut buf = [0u8; MSG_SIZE];
1266 user.copy_to(&mut buf);
1267 let mut msg = crate::ipc::message::ipc_message_from_raw(&buf);
1268 msg.sender = task.id.as_u64();
1269 if msg.flags != 0 {
1270 let transfer_required = CapPermissions {
1271 read: false,
1272 write: false,
1273 execute: false,
1274 grant: true,
1275 revoke: false,
1276 };
1277 if caps
1278 .get_with_permissions(CapId::from_raw(msg.flags as u64), transfer_required)
1279 .is_none()
1280 {
1281 return Err(SyscallError::PermissionDenied);
1282 }
1283 }
1284
1285 let port_id = PortId::from_u64(cap.resource as u64);
1286 let port = port::get_port(port_id).ok_or(SyscallError::BadHandle)?;
1287 port.send(msg).map_err(SyscallError::from)?;
1288
1289 let reply_msg = reply::wait_for_reply(task.id);
1290 let mut out_buf = [0u8; MSG_SIZE];
1291 crate::ipc::message::ipc_message_to_raw(&reply_msg, &mut out_buf);
1292 let user = UserSliceWrite::new(_msg_ptr, MSG_SIZE)?;
1293 user.copy_from(&out_buf);
1294 Ok(0)
1295}
1296
1297fn sys_ipc_reply(_msg_ptr: u64) -> Result<u64, SyscallError> {
1299 if _msg_ptr == 0 {
1300 return Err(SyscallError::Fault);
1301 }
1302 const MSG_SIZE: usize = core::mem::size_of::<IpcMessage>();
1303 let user = UserSliceRead::new(_msg_ptr, MSG_SIZE)?;
1304 let mut buf = [0u8; MSG_SIZE];
1305 user.copy_to(&mut buf);
1306 let msg = crate::ipc::message::ipc_message_from_raw(&buf);
1307
1308 let target = crate::process::TaskId::from_u64(msg.sender);
1309 let mut msg = msg;
1310 if msg.flags != 0 {
1311 let sender = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1312 let sender_caps = unsafe { &mut *sender.process.capabilities.get() };
1313 let dup = sender_caps
1314 .duplicate(CapId::from_raw(msg.flags as u64))
1315 .ok_or(SyscallError::PermissionDenied)?;
1316
1317 let receiver = crate::process::get_task_by_id(target).ok_or(SyscallError::BadHandle)?;
1318 let receiver_caps = unsafe { &mut *receiver.process.capabilities.get() };
1319 let new_id = receiver_caps.insert(dup);
1320 if new_id.as_u64() > u32::MAX as u64 {
1321 return Err(SyscallError::InvalidArgument);
1322 }
1323 msg.flags = new_id.as_u64() as u32;
1324 }
1325
1326 reply::deliver_reply(target, msg).map_err(|_| SyscallError::BadHandle)?;
1327 Ok(0)
1328}
1329
1330fn sys_ipc_bind_port(port: u64, _path_ptr: u64, _path_len: u64) -> Result<u64, SyscallError> {
1332 crate::silo::enforce_registry_bind_for_current_task()?;
1333 crate::silo::enforce_cap_for_current_task(port)?;
1334 if _path_ptr == 0 || _path_len == 0 {
1335 return Err(SyscallError::Fault);
1336 }
1337 const MAX_PATH_LEN: usize = 4096;
1338 if _path_len as usize > MAX_PATH_LEN {
1339 return Err(SyscallError::InvalidArgument);
1340 }
1341 let user = UserSliceRead::new(_path_ptr, _path_len as usize)?;
1342 let bytes = user.read_to_vec();
1343 let path = core::str::from_utf8(&bytes).map_err(SyscallError::from)?;
1344
1345 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1346 let caps = unsafe { &*task.process.capabilities.get() };
1347 let cap = caps
1348 .get_with_permissions(
1349 CapId::from_raw(port),
1350 CapPermissions {
1351 read: true,
1352 write: true,
1353 execute: false,
1354 grant: true,
1355 revoke: false,
1356 },
1357 )
1358 .ok_or(SyscallError::PermissionDenied)?;
1359 if cap.resource_type != ResourceType::IpcPort {
1360 return Err(SyscallError::BadHandle);
1361 }
1362
1363 crate::vfs::mount(
1364 path,
1365 Arc::new(crate::vfs::IpcScheme::new(PortId::from_u64(
1366 cap.resource as u64,
1367 ))),
1368 )?;
1369 let _ = crate::namespace::bind(path, cap.resource as u64);
1370 let _ = crate::silo::set_current_silo_label_from_path(path);
1371
1372 let should_bootstrap = path == "/" || path.starts_with("/srv/strate-fs-");
1379 if should_bootstrap {
1380 let mut seeded_handle: u32 = 0;
1381 if let Some(device) = crate::hardware::storage::virtio_block::get_device() {
1382 let volume_resource = device as *const _ as usize;
1383 let volume_perms = CapPermissions {
1384 read: true,
1385 write: true,
1386 execute: false,
1387 grant: true,
1388 revoke: true,
1389 };
1390 let volume_cap = crate::capability::get_capability_manager().create_capability(
1391 ResourceType::Volume,
1392 volume_resource,
1393 volume_perms,
1394 );
1395 let task_caps = unsafe { &mut *task.process.capabilities.get() };
1396 let id = task_caps.insert(volume_cap);
1397 let _ = crate::silo::register_current_task_granted_resource(
1398 ResourceType::Volume,
1399 volume_resource,
1400 volume_perms,
1401 );
1402 if id.as_u64() <= u32::MAX as u64 {
1403 seeded_handle = id.as_u64() as u32;
1404 }
1405 log::info!(
1406 "ipc_bind_port('/'): seeded volume capability handle={} for task {:?}",
1407 id.as_u64(),
1408 task.id
1409 );
1410 }
1411
1412 const BOOTSTRAP_MSG_TYPE: u32 = 0x10;
1419 let mut boot_msg = IpcMessage::new(BOOTSTRAP_MSG_TYPE);
1420 boot_msg.sender = task.id.as_u64();
1423 boot_msg.flags = seeded_handle;
1424 let label_owned = crate::silo::current_task_silo_label().unwrap_or_else(|| {
1425 if path == "/" {
1426 alloc::string::String::from("root")
1427 } else {
1428 alloc::string::String::from(
1429 path.rsplit('/')
1430 .find(|part| !part.is_empty())
1431 .unwrap_or("default"),
1432 )
1433 }
1434 });
1435 let label_bytes = label_owned.as_bytes();
1436 let max_len = boot_msg.payload.len().saturating_sub(1);
1437 let copy_len = core::cmp::min(label_bytes.len(), max_len);
1438 boot_msg.payload[0] = copy_len as u8;
1439 if copy_len > 0 {
1440 boot_msg.payload[1..1 + copy_len].copy_from_slice(&label_bytes[..copy_len]);
1441 }
1442
1443 let port_id = PortId::from_u64(cap.resource as u64);
1444 if let Some(p) = port::get_port(port_id) {
1445 if p.send(boot_msg).is_ok() {
1446 log::info!(
1447 "ipc_bind_port('{}'): queued bootstrap message (handle={}, label={})",
1448 path,
1449 seeded_handle,
1450 label_owned
1451 );
1452 } else {
1453 log::warn!(
1454 "ipc_bind_port('{}'): failed to queue bootstrap message",
1455 path
1456 );
1457 }
1458 } else {
1459 log::warn!(
1460 "ipc_bind_port('{}'): bound port disappeared before bootstrap",
1461 path
1462 );
1463 }
1464 }
1465 Ok(0)
1466}
1467
1468fn sys_ipc_unbind_port(path_ptr: u64, path_len: u64) -> Result<u64, SyscallError> {
1470 crate::silo::require_silo_admin()?;
1471 if path_ptr == 0 || path_len == 0 {
1472 return Err(SyscallError::Fault);
1473 }
1474 const MAX_PATH_LEN: usize = 4096;
1475 if path_len as usize > MAX_PATH_LEN {
1476 return Err(SyscallError::InvalidArgument);
1477 }
1478 let user = UserSliceRead::new(path_ptr, path_len as usize)?;
1479 let bytes = user.read_to_vec();
1480 let path = core::str::from_utf8(&bytes).map_err(SyscallError::from)?;
1481 let _ = crate::namespace::unbind(path);
1482 crate::vfs::unmount(path)?;
1483 Ok(0)
1484}
1485
1486fn sys_ipc_ring_create(_size: u64) -> Result<u64, SyscallError> {
1488 let size = usize::try_from(_size).map_err(|_| SyscallError::InvalidArgument)?;
1489 let ring_id = shared_ring::create_ring(size).map_err(|e| match e {
1490 shared_ring::RingError::InvalidSize => SyscallError::InvalidArgument,
1491 shared_ring::RingError::Alloc => SyscallError::OutOfMemory,
1492 shared_ring::RingError::NotFound => SyscallError::NotFound,
1493 })?;
1494
1495 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1496 let cap = get_capability_manager().create_capability(
1497 ResourceType::SharedRing,
1498 ring_id.as_u64() as usize,
1499 CapPermissions {
1500 read: true,
1501 write: true,
1502 execute: false,
1503 grant: true,
1504 revoke: true,
1505 },
1506 );
1507 let cap_id = unsafe { (&mut *task.process.capabilities.get()).insert(cap) };
1508 Ok(cap_id.as_u64())
1509}
1510
1511fn sys_ipc_ring_map(ring: u64, _out_ptr: u64) -> Result<u64, SyscallError> {
1513 crate::silo::enforce_cap_for_current_task(ring)?;
1514 if _out_ptr == 0 {
1515 return Err(SyscallError::Fault);
1516 }
1517
1518 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1519 let caps = unsafe { &*task.process.capabilities.get() };
1520 let required = CapPermissions {
1521 read: true,
1522 write: true,
1523 execute: false,
1524 grant: false,
1525 revoke: false,
1526 };
1527 let cap = caps
1528 .get_with_permissions(CapId::from_raw(ring), required)
1529 .ok_or(SyscallError::PermissionDenied)?;
1530 if cap.resource_type != ResourceType::SharedRing {
1531 return Err(SyscallError::BadHandle);
1532 }
1533
1534 let ring_id = RingId::from_u64(cap.resource as u64);
1535 let ring_obj = shared_ring::get_ring(ring_id).ok_or(SyscallError::BadHandle)?;
1536 let frame_phys_addrs = ring_obj.frame_phys_addrs();
1537 let page_count = ring_obj.page_count();
1538 let map_size = page_count
1539 .checked_mul(4096)
1540 .ok_or(SyscallError::InvalidArgument)? as u64;
1541
1542 let addr_space = unsafe { &*task.process.address_space.get() };
1543 let base = addr_space
1544 .find_free_vma_range(
1545 super::mmap::MMAP_BASE,
1546 page_count,
1547 crate::memory::address_space::VmaPageSize::Small,
1548 )
1549 .ok_or(SyscallError::OutOfMemory)?;
1550
1551 addr_space
1552 .map_shared_frames(
1553 base,
1554 &frame_phys_addrs,
1555 crate::memory::address_space::VmaFlags {
1556 readable: true,
1557 writable: true,
1558 executable: false,
1559 user_accessible: true,
1560 },
1561 crate::memory::address_space::VmaType::Anonymous,
1562 )
1563 .map_err(|_| SyscallError::OutOfMemory)?;
1564
1565 let out = UserSliceWrite::new(_out_ptr, core::mem::size_of::<u64>())?;
1566 out.copy_from(&base.to_ne_bytes());
1567 Ok(map_size)
1568}
1569
1570fn sys_sem_create(initial: u64) -> Result<u64, SyscallError> {
1572 let initial = u32::try_from(initial).map_err(|_| SyscallError::InvalidArgument)?;
1573 let sem_id = semaphore::create_semaphore(initial).map_err(|e| match e {
1574 semaphore::SemaphoreError::InvalidValue => SyscallError::InvalidArgument,
1575 semaphore::SemaphoreError::WouldBlock => SyscallError::Again,
1576 semaphore::SemaphoreError::Destroyed => SyscallError::Pipe,
1577 semaphore::SemaphoreError::NotFound => SyscallError::NotFound,
1578 })?;
1579
1580 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1581 let cap = get_capability_manager().create_capability(
1582 ResourceType::Semaphore,
1583 sem_id.as_u64() as usize,
1584 CapPermissions {
1585 read: true,
1586 write: true,
1587 execute: false,
1588 grant: true,
1589 revoke: true,
1590 },
1591 );
1592 let cap_id = unsafe { (&mut *task.process.capabilities.get()).insert(cap) };
1593 Ok(cap_id.as_u64())
1594}
1595
1596fn resolve_sem(
1598 handle: u64,
1599 required: CapPermissions,
1600) -> Result<alloc::sync::Arc<semaphore::PosixSemaphore>, SyscallError> {
1601 crate::silo::enforce_cap_for_current_task(handle)?;
1602 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1603 let caps = unsafe { &*task.process.capabilities.get() };
1604 let cap = caps
1605 .get_with_permissions(CapId::from_raw(handle), required)
1606 .ok_or(SyscallError::PermissionDenied)?;
1607 if cap.resource_type != ResourceType::Semaphore {
1608 return Err(SyscallError::BadHandle);
1609 }
1610 let id = SemId::from_u64(cap.resource as u64);
1611 semaphore::get_semaphore(id).ok_or(SyscallError::BadHandle)
1612}
1613
1614fn sys_sem_wait(handle: u64) -> Result<u64, SyscallError> {
1616 let sem = resolve_sem(
1617 handle,
1618 CapPermissions {
1619 read: true,
1620 write: false,
1621 execute: false,
1622 grant: false,
1623 revoke: false,
1624 },
1625 )?;
1626 sem.wait().map_err(|e| match e {
1627 semaphore::SemaphoreError::WouldBlock => SyscallError::Again,
1628 semaphore::SemaphoreError::Destroyed => SyscallError::Pipe,
1629 semaphore::SemaphoreError::InvalidValue => SyscallError::InvalidArgument,
1630 semaphore::SemaphoreError::NotFound => SyscallError::NotFound,
1631 })?;
1632 Ok(0)
1633}
1634
1635fn sys_sem_trywait(handle: u64) -> Result<u64, SyscallError> {
1637 let sem = resolve_sem(
1638 handle,
1639 CapPermissions {
1640 read: true,
1641 write: false,
1642 execute: false,
1643 grant: false,
1644 revoke: false,
1645 },
1646 )?;
1647 sem.try_wait().map_err(|e| match e {
1648 semaphore::SemaphoreError::WouldBlock => SyscallError::Again,
1649 semaphore::SemaphoreError::Destroyed => SyscallError::Pipe,
1650 semaphore::SemaphoreError::InvalidValue => SyscallError::InvalidArgument,
1651 semaphore::SemaphoreError::NotFound => SyscallError::NotFound,
1652 })?;
1653 Ok(0)
1654}
1655
1656fn sys_sem_post(handle: u64) -> Result<u64, SyscallError> {
1658 let sem = resolve_sem(
1659 handle,
1660 CapPermissions {
1661 read: false,
1662 write: true,
1663 execute: false,
1664 grant: false,
1665 revoke: false,
1666 },
1667 )?;
1668 sem.post().map_err(|e| match e {
1669 semaphore::SemaphoreError::WouldBlock => SyscallError::Again,
1670 semaphore::SemaphoreError::Destroyed => SyscallError::Pipe,
1671 semaphore::SemaphoreError::InvalidValue => SyscallError::InvalidArgument,
1672 semaphore::SemaphoreError::NotFound => SyscallError::NotFound,
1673 })?;
1674 Ok(0)
1675}
1676
1677fn sys_sem_close(handle: u64) -> Result<u64, SyscallError> {
1679 crate::silo::enforce_cap_for_current_task(handle)?;
1680 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1681 let caps = unsafe { &mut *task.process.capabilities.get() };
1682 let cap = caps
1683 .remove(CapId::from_raw(handle))
1684 .ok_or(SyscallError::BadHandle)?;
1685 if cap.resource_type != ResourceType::Semaphore {
1686 return Err(SyscallError::BadHandle);
1687 }
1688 semaphore::destroy_semaphore(SemId::from_u64(cap.resource as u64)).map_err(|e| match e {
1689 semaphore::SemaphoreError::WouldBlock => SyscallError::Again,
1690 semaphore::SemaphoreError::Destroyed => SyscallError::Pipe,
1691 semaphore::SemaphoreError::InvalidValue => SyscallError::InvalidArgument,
1692 semaphore::SemaphoreError::NotFound => SyscallError::NotFound,
1693 })?;
1694 Ok(0)
1695}
1696
1697use strat9_abi::data::{
1698 PciAddress as PciAddressAbi, PciDeviceInfo as PciDeviceInfoAbi,
1699 PciProbeCriteria as PciProbeCriteriaAbi, PCI_MATCH_CLASS_CODE, PCI_MATCH_DEVICE_ID,
1700 PCI_MATCH_PROG_IF, PCI_MATCH_SUBCLASS, PCI_MATCH_VENDOR_ID,
1701};
1702
1703fn read_pci_address(addr_ptr: u64) -> Result<pci::PciAddress, SyscallError> {
1705 if addr_ptr == 0 {
1706 return Err(SyscallError::Fault);
1707 }
1708 let user = UserSliceRead::new(addr_ptr, core::mem::size_of::<PciAddressAbi>())?;
1709 let mut raw = [0u8; core::mem::size_of::<PciAddressAbi>()];
1710 user.copy_to(&mut raw);
1711 let abi = unsafe { core::ptr::read_unaligned(raw.as_ptr() as *const PciAddressAbi) };
1712 if abi.device > 31 || abi.function > 7 {
1713 return Err(SyscallError::InvalidArgument);
1714 }
1715 Ok(pci::PciAddress::new(abi.bus, abi.device, abi.function))
1716}
1717
1718fn sys_pci_enum(criteria_ptr: u64, out_ptr: u64, max_entries: u64) -> Result<u64, SyscallError> {
1720 if criteria_ptr == 0 || out_ptr == 0 {
1721 return Err(SyscallError::Fault);
1722 }
1723 if max_entries == 0 {
1724 return Ok(0);
1725 }
1726 let max_entries = core::cmp::min(max_entries as usize, 4096);
1727 let user_criteria =
1728 UserSliceRead::new(criteria_ptr, core::mem::size_of::<PciProbeCriteriaAbi>())?;
1729 let mut criteria_bytes = [0u8; core::mem::size_of::<PciProbeCriteriaAbi>()];
1730 user_criteria.copy_to(&mut criteria_bytes);
1731 let criteria_abi =
1732 unsafe { core::ptr::read_unaligned(criteria_bytes.as_ptr() as *const PciProbeCriteriaAbi) };
1733
1734 let criteria = pci::ProbeCriteria {
1735 vendor_id: if (criteria_abi.match_flags & PCI_MATCH_VENDOR_ID) != 0 {
1736 Some(criteria_abi.vendor_id)
1737 } else {
1738 None
1739 },
1740 device_id: if (criteria_abi.match_flags & PCI_MATCH_DEVICE_ID) != 0 {
1741 Some(criteria_abi.device_id)
1742 } else {
1743 None
1744 },
1745 class_code: if (criteria_abi.match_flags & PCI_MATCH_CLASS_CODE) != 0 {
1746 Some(criteria_abi.class_code)
1747 } else {
1748 None
1749 },
1750 subclass: if (criteria_abi.match_flags & PCI_MATCH_SUBCLASS) != 0 {
1751 Some(criteria_abi.subclass)
1752 } else {
1753 None
1754 },
1755 prog_if: if (criteria_abi.match_flags & PCI_MATCH_PROG_IF) != 0 {
1756 Some(criteria_abi.prog_if)
1757 } else {
1758 None
1759 },
1760 };
1761
1762 let devices = pci::probe_all(criteria);
1763 let count = core::cmp::min(devices.len(), max_entries);
1764 let mut out = alloc::vec::Vec::<PciDeviceInfoAbi>::with_capacity(count);
1765 for dev in devices.into_iter().take(count) {
1766 out.push(PciDeviceInfoAbi {
1767 address: PciAddressAbi {
1768 bus: dev.address.bus,
1769 device: dev.address.device,
1770 function: dev.address.function,
1771 _reserved: 0,
1772 },
1773 vendor_id: dev.vendor_id,
1774 device_id: dev.device_id,
1775 class_code: dev.class_code,
1776 subclass: dev.subclass,
1777 prog_if: dev.prog_if,
1778 revision: dev.revision,
1779 header_type: dev.header_type,
1780 interrupt_line: dev.interrupt_line,
1781 interrupt_pin: dev.interrupt_pin,
1782 _reserved: 0,
1783 });
1784 }
1785 let out_bytes_len = out
1786 .len()
1787 .checked_mul(core::mem::size_of::<PciDeviceInfoAbi>())
1788 .ok_or(SyscallError::InvalidArgument)?;
1789 let user_out = UserSliceWrite::new(out_ptr, out_bytes_len)?;
1790 let out_bytes =
1791 unsafe { core::slice::from_raw_parts(out.as_ptr() as *const u8, out_bytes_len) };
1792 user_out.copy_from(out_bytes);
1793 Ok(out.len() as u64)
1794}
1795
1796fn sys_pci_cfg_read(addr_ptr: u64, offset: u64, width: u64) -> Result<u64, SyscallError> {
1798 let dev_addr = read_pci_address(addr_ptr)?;
1799 let offset = u8::try_from(offset).map_err(|_| SyscallError::InvalidArgument)?;
1800 let width = u8::try_from(width).map_err(|_| SyscallError::InvalidArgument)?;
1801 if !matches!(width, 1 | 2 | 4) {
1802 return Err(SyscallError::InvalidArgument);
1803 }
1804 if offset > 0xFC || (offset as u16 + width as u16) > 0x100 {
1805 return Err(SyscallError::InvalidArgument);
1806 }
1807 if (width == 2 && (offset & 1) != 0) || (width == 4 && (offset & 3) != 0) {
1808 return Err(SyscallError::InvalidArgument);
1809 }
1810 let dev = pci::all_devices()
1811 .into_iter()
1812 .find(|d| d.address == dev_addr)
1813 .ok_or(SyscallError::NotFound)?;
1814 let value = match width {
1815 1 => dev.read_config_u8(offset) as u32,
1816 2 => dev.read_config_u16(offset) as u32,
1817 _ => dev.read_config_u32(offset),
1818 };
1819 Ok(value as u64)
1820}
1821
1822fn sys_pci_cfg_write(
1824 addr_ptr: u64,
1825 offset: u64,
1826 width: u64,
1827 value: u64,
1828) -> Result<u64, SyscallError> {
1829 let dev_addr = read_pci_address(addr_ptr)?;
1830 let offset = u8::try_from(offset).map_err(|_| SyscallError::InvalidArgument)?;
1831 let width = u8::try_from(width).map_err(|_| SyscallError::InvalidArgument)?;
1832 if !matches!(width, 1 | 2 | 4) {
1833 return Err(SyscallError::InvalidArgument);
1834 }
1835 if offset > 0xFC || (offset as u16 + width as u16) > 0x100 {
1836 return Err(SyscallError::InvalidArgument);
1837 }
1838 if (width == 2 && (offset & 1) != 0) || (width == 4 && (offset & 3) != 0) {
1839 return Err(SyscallError::InvalidArgument);
1840 }
1841 let dev = pci::all_devices()
1842 .into_iter()
1843 .find(|d| d.address == dev_addr)
1844 .ok_or(SyscallError::NotFound)?;
1845 match width {
1846 1 => dev.write_config_u8(offset, value as u8),
1847 2 => dev.write_config_u16(offset, value as u16),
1848 _ => dev.write_config_u32(offset, value as u32),
1849 }
1850 Ok(0)
1851}
1852
1853fn sys_chan_create(capacity: u64) -> Result<u64, SyscallError> {
1860 let cap = capacity.clamp(1, 1024) as usize;
1861 let chan_id = channel::create_channel(cap);
1862
1863 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1865 let caps = unsafe { &mut *task.process.capabilities.get() };
1866 let cap_id = caps.insert(crate::capability::Capability {
1867 id: crate::capability::CapId::new(),
1868 permissions: crate::capability::CapPermissions {
1869 read: true,
1870 write: true,
1871 execute: false,
1872 grant: true,
1873 revoke: false,
1874 },
1875 resource_type: ResourceType::Channel,
1876 resource: chan_id.as_u64() as usize,
1877 });
1878
1879 log::debug!(
1880 "syscall: CHAN_CREATE(cap={}) → chan={} handle={}",
1881 cap,
1882 chan_id,
1883 cap_id.as_u64()
1884 );
1885 Ok(cap_id.as_u64())
1886}
1887
1888fn sys_chan_send(handle: u64, msg_ptr: u64) -> Result<u64, SyscallError> {
1892 crate::silo::enforce_cap_for_current_task(handle)?;
1893
1894 let user_slice = UserSliceRead::new(msg_ptr, 64).map_err(SyscallError::from)?;
1896 let mut msg = IpcMessage::new(0);
1897 let n = user_slice.copy_to(unsafe {
1899 core::slice::from_raw_parts_mut(&mut msg as *mut IpcMessage as *mut u8, 64)
1900 });
1901 if n != 64 {
1902 return Err(SyscallError::Fault);
1903 }
1904
1905 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1907 msg.sender = task.id.as_u64();
1908
1909 let caps = unsafe { &*task.process.capabilities.get() };
1911 let cap = caps
1912 .get(crate::capability::CapId::from_raw(handle))
1913 .ok_or(SyscallError::BadHandle)?;
1914 if cap.resource_type != ResourceType::Channel || !cap.permissions.write {
1915 return Err(SyscallError::PermissionDenied);
1916 }
1917 let chan_id = ChanId::from_u64(cap.resource as u64);
1918
1919 let chan = channel::get_channel(chan_id).ok_or(SyscallError::BadHandle)?;
1920 chan.send(msg).map_err(SyscallError::from)?;
1921
1922 Ok(0)
1923}
1924
1925fn sys_chan_recv(handle: u64, msg_ptr: u64) -> Result<u64, SyscallError> {
1929 crate::silo::enforce_cap_for_current_task(handle)?;
1930
1931 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1932 let caps = unsafe { &*task.process.capabilities.get() };
1933 let cap = caps
1934 .get(crate::capability::CapId::from_raw(handle))
1935 .ok_or(SyscallError::BadHandle)?;
1936 if cap.resource_type != ResourceType::Channel || !cap.permissions.read {
1937 return Err(SyscallError::PermissionDenied);
1938 }
1939 let chan_id = ChanId::from_u64(cap.resource as u64);
1940
1941 let chan = channel::get_channel(chan_id).ok_or(SyscallError::BadHandle)?;
1942 let msg = chan.recv().map_err(SyscallError::from)?;
1943
1944 let user_slice = UserSliceWrite::new(msg_ptr, 64).map_err(SyscallError::from)?;
1946 let n = user_slice.copy_from(unsafe {
1948 core::slice::from_raw_parts(&msg as *const IpcMessage as *const u8, 64)
1949 });
1950 if n != 64 {
1951 return Err(SyscallError::Fault);
1952 }
1953
1954 Ok(0)
1955}
1956
1957fn sys_chan_try_recv(handle: u64, msg_ptr: u64) -> Result<u64, SyscallError> {
1961 crate::silo::enforce_cap_for_current_task(handle)?;
1962
1963 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1964 let caps = unsafe { &*task.process.capabilities.get() };
1965 let cap = caps
1966 .get(crate::capability::CapId::from_raw(handle))
1967 .ok_or(SyscallError::BadHandle)?;
1968 if cap.resource_type != ResourceType::Channel || !cap.permissions.read {
1969 return Err(SyscallError::PermissionDenied);
1970 }
1971 let chan_id = ChanId::from_u64(cap.resource as u64);
1972
1973 let chan = channel::get_channel(chan_id).ok_or(SyscallError::BadHandle)?;
1974 match chan.try_recv() {
1975 Ok(msg) => {
1976 let user_slice = UserSliceWrite::new(msg_ptr, 64).map_err(SyscallError::from)?;
1977 let n = user_slice.copy_from(unsafe {
1979 core::slice::from_raw_parts(&msg as *const IpcMessage as *const u8, 64)
1980 });
1981 if n != 64 {
1982 return Err(SyscallError::Fault);
1983 }
1984 Ok(0)
1985 }
1986 Err(e) => Err(SyscallError::from(e)),
1987 }
1988}
1989
1990fn sys_chan_close(handle: u64) -> Result<u64, SyscallError> {
1994 crate::silo::enforce_cap_for_current_task(handle)?;
1995
1996 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
1997 let caps = unsafe { &mut *task.process.capabilities.get() };
1998 let cap = caps
1999 .remove(crate::capability::CapId::from_raw(handle))
2000 .ok_or(SyscallError::BadHandle)?;
2001 if cap.resource_type != ResourceType::Channel {
2002 return Err(SyscallError::BadHandle);
2003 }
2004 let chan_id = ChanId::from_u64(cap.resource as u64);
2005 channel::destroy_channel(chan_id).map_err(SyscallError::from)?;
2006
2007 log::debug!("syscall: CHAN_CLOSE(handle={}) → chan={}", handle, chan_id);
2008 Ok(0)
2009}