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