1use crate::ipc::{channel, port, semaphore, shared_ring, ChanId, PortId, RingId, SemId};
17
18use super::{
19 chan, debug, error::SyscallError, exec::sys_execve, fork::sys_fork, ipc_port, ipc_ring, net,
20 numbers::*, pci, process as proc_sys, semaphore as sem_handler, transport, volume,
21 SyscallFrame,
22};
23use crate::{
24 async_io::syscall as async_sys,
25 capability::{release_capability, CapId, CapPermissions, ResourceType},
26 memory::{UserSliceRead, UserSliceWrite},
27 process::current_task_clone,
28 silo,
29};
30use core::sync::atomic::Ordering;
31static SYSCALL_DIAG_DONE: core::sync::atomic::AtomicBool =
33 core::sync::atomic::AtomicBool::new(false);
34
35static SYSCALL_TRACE_COUNT: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
38
39#[no_mangle]
51pub extern "C" fn __strat9_syscall_dispatch(frame: &mut SyscallFrame) -> u64 {
52 let syscall_num = frame.rax as usize;
53 let arg1 = frame.rdi;
54 let arg2 = frame.rsi;
55 let arg3 = frame.rdx;
56
57 if !SYSCALL_DIAG_DONE.swap(true, core::sync::atomic::Ordering::Relaxed) {
59 crate::e9_println!(
60 "[syscall-FIRST] nr={} rip={:#x} tid={:?}",
61 syscall_num,
62 frame.rcx,
63 crate::process::current_task_id().map(|t| t.as_u64())
64 );
65 }
66 let arg4 = frame.r10;
67 let arg5 = frame.r8;
68 let _arg6 = frame.r9;
69
70 {
81 let n = SYSCALL_TRACE_COUNT.load(core::sync::atomic::Ordering::Relaxed);
82 if n < 20 || n % 10_000 == 0 || n == u64::MAX {
83 let n = SYSCALL_TRACE_COUNT.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
85 if n < 20 || n % 10_000 == 0 {
86 if let Some(tid) = crate::process::current_task_id() {
87 crate::e9_println!(
88 "[syscall] ENTER n={} tid={} nr={} arg1={:#x} arg2={:#x} rip={:#x} cpu={}",
89 n,
90 tid,
91 syscall_num,
92 arg1,
93 arg2,
94 frame.rcx,
95 crate::arch::percpu::current_cpu_index()
96 );
97 }
98 }
99 } else {
100 SYSCALL_TRACE_COUNT.store(n + 1, core::sync::atomic::Ordering::Relaxed);
103 }
104 }
105
106 let result = match syscall_num {
107 SYS_NULL => sys_null(),
108 SYS_HANDLE_DUPLICATE => sys_handle_duplicate(arg1),
109 SYS_HANDLE_CLOSE => sys_handle_close(arg1),
110 SYS_HANDLE_WAIT => sys_handle_wait(arg1, arg2),
111 SYS_HANDLE_GRANT => sys_handle_grant(arg1, arg2),
112 SYS_HANDLE_REVOKE => sys_handle_revoke(arg1),
113 SYS_HANDLE_INFO => sys_handle_info(arg1, arg2),
114
115 SYS_MMAP => super::mmap::sys_mmap(arg1, arg2, arg3 as u32, arg4 as u32, frame.r8, frame.r9),
117 SYS_MUNMAP => super::mmap::sys_munmap(arg1, arg2),
118 SYS_BRK => super::mmap::sys_brk(arg1),
119 SYS_MREMAP => super::mmap::sys_mremap(arg1, arg2, arg3, arg4),
120 SYS_MPROTECT => super::mmap::sys_mprotect(arg1, arg2, arg3),
121 SYS_MEM_REGION_EXPORT => super::mmap::sys_mem_region_export(arg1),
122 SYS_MEM_REGION_MAP => super::mmap::sys_mem_region_map(arg1, arg2, arg3),
123 SYS_MEM_REGION_INFO => super::mmap::sys_mem_region_info(arg1, arg2),
124
125 SYS_PROC_EXIT => sys_proc_exit(arg1),
127 SYS_PROC_YIELD => sys_proc_yield(),
128 SYS_PROC_FORK => sys_fork(frame).map(|result| result.child_pid as u64),
129 SYS_PROC_GETPID | SYS_GETPID => proc_sys::sys_getpid(),
130 SYS_PROC_GETPPID => proc_sys::sys_getppid(),
131 SYS_GETTID => proc_sys::sys_gettid(),
132 SYS_PROC_WAITPID => {
133 super::wait::sys_waitpid(arg1 as i64, arg2, arg3 as u32).map(|pid| pid as u64)
134 }
135 SYS_PROC_WAIT => super::wait::sys_wait(arg1),
136 SYS_PROC_EXECVE => sys_execve(frame, arg1, arg2, arg3),
137
138 SYS_FCNTL => super::fcntl::sys_fcntl(arg1, arg2, arg3),
140 SYS_SETPGID => proc_sys::sys_setpgid(arg1 as i64, arg2 as i64),
141 SYS_GETPGID => proc_sys::sys_getpgid(arg1 as i64),
142 SYS_SETSID => proc_sys::sys_setsid(),
143 SYS_GETPGRP => proc_sys::sys_getpgrp(),
144 SYS_GETSID => proc_sys::sys_getsid(arg1 as i64),
145
146 SYS_GETUID => proc_sys::sys_getuid(),
147 SYS_GETEUID => proc_sys::sys_geteuid(),
148 SYS_GETGID => proc_sys::sys_getgid(),
149 SYS_GETEGID => proc_sys::sys_getegid(),
150 SYS_SETUID => proc_sys::sys_setuid(arg1),
151 SYS_SETGID => proc_sys::sys_setgid(arg1),
152 SYS_THREAD_CREATE => proc_sys::sys_thread_create(frame, arg1, arg2, arg3, arg4, frame.r8),
153 SYS_THREAD_JOIN => proc_sys::sys_thread_join(arg1, arg2, arg3),
154 SYS_THREAD_EXIT => proc_sys::sys_thread_exit(arg1),
155 SYS_UNAME => sys_uname(arg1),
156 SYS_SET_TID_ADDRESS => proc_sys::sys_set_tid_address(arg1),
158 SYS_EXIT_GROUP => proc_sys::sys_exit_group(arg1),
159 SYS_ARCH_PRCTL => proc_sys::sys_arch_prctl(arg1, arg2),
161
162 SYS_TGKILL => proc_sys::sys_tgkill(arg1, arg2, arg3),
164 SYS_RT_SIGRETURN => super::signal::sys_rt_sigreturn(frame),
165 SYS_FUTEX_WAIT => super::futex::sys_futex_wait(arg1, arg2 as u32, arg3),
167 SYS_FUTEX_WAKE => super::futex::sys_futex_wake(arg1, arg2 as u32),
168 SYS_FUTEX_REQUEUE => super::futex::sys_futex_requeue(arg1, arg2 as u32, arg3 as u32, arg4),
169 SYS_FUTEX_CMP_REQUEUE => super::futex::sys_futex_cmp_requeue(
170 arg1,
171 arg2 as u32,
172 arg3 as u32,
173 arg4,
174 frame.r8 as u32,
175 ),
176 SYS_FUTEX_WAKE_OP => {
177 super::futex::sys_futex_wake_op(arg1, arg2 as u32, arg3 as u32, arg4, frame.r8 as u32)
178 }
179 SYS_KILL => super::signal::sys_kill(arg1 as i64, arg2 as u32),
180 SYS_SIGPROCMASK => sys_sigprocmask(arg1 as i32, arg2, arg3),
181 SYS_SIGACTION => super::signal::sys_sigaction(arg1, arg2, arg3),
182 SYS_SIGALTSTACK => super::signal::sys_sigaltstack(arg1, arg2),
183 SYS_SIGPENDING => super::signal::sys_sigpending(arg1),
184 SYS_SIGSUSPEND => super::signal::sys_sigsuspend(arg1),
185 SYS_SIGTIMEDWAIT => super::signal::sys_sigtimedwait(arg1, arg2, arg3),
186 SYS_SIGQUEUE => super::signal::sys_sigqueue(arg1 as i64, arg2 as u32, arg3),
187 SYS_KILLPG => super::signal::sys_killpg(arg1, arg2 as u32),
188 SYS_GETITIMER => super::signal::sys_getitimer(arg1 as u32, arg2),
189 SYS_SETITIMER => super::signal::sys_setitimer(arg1 as u32, arg2, arg3),
190
191 SYS_IPC_CREATE_PORT => ipc_port::sys_ipc_create_port(arg1),
193 SYS_IPC_SEND => ipc_port::sys_ipc_send(arg1, arg2),
194 SYS_IPC_RECV => ipc_port::sys_ipc_recv(arg1, arg2),
195 SYS_IPC_TRY_RECV => ipc_port::sys_ipc_try_recv(arg1, arg2),
196 SYS_IPC_CONNECT => ipc_port::sys_ipc_connect(arg1, arg2),
197 SYS_IPC_CALL => ipc_port::sys_ipc_call(arg1, arg2),
198 SYS_IPC_REPLY => ipc_port::sys_ipc_reply(arg1),
199 SYS_IPC_BIND_PORT => ipc_port::sys_ipc_bind_port(arg1, arg2, arg3),
200 SYS_IPC_UNBIND_PORT => ipc_port::sys_ipc_unbind_port(arg1, arg2),
201
202 SYS_IPC_RING_CREATE => ipc_ring::sys_ipc_ring_create(arg1),
204 SYS_IPC_RING_MAP => ipc_ring::sys_ipc_ring_map(arg1, arg2),
205
206 SYS_SEM_CREATE => sem_handler::sys_sem_create(arg1),
208 SYS_SEM_WAIT => sem_handler::sys_sem_wait(arg1),
209 SYS_SEM_TRYWAIT => sem_handler::sys_sem_trywait(arg1),
210 SYS_SEM_POST => sem_handler::sys_sem_post(arg1),
211 SYS_SEM_CLOSE => sem_handler::sys_sem_close(arg1),
212
213 SYS_ASYNC_SETUP => async_sys::sys_async_setup(arg1, arg2),
215 SYS_ASYNC_ENTER => async_sys::sys_async_enter(arg1, arg2, arg3, arg4),
216 SYS_ASYNC_CANCEL => async_sys::sys_async_cancel(arg1, arg2, arg3),
217 SYS_ASYNC_MAP => async_sys::sys_async_map(arg1, arg2),
218 SYS_ASYNC_DESTROY => async_sys::sys_async_destroy(arg1, arg2),
219
220 SYS_TRANSPORT_CREATE => transport::sys_transport_create(arg1, arg2),
222 SYS_TRANSPORT_SEND => transport::sys_transport_send(arg1, arg2, arg3),
223 SYS_TRANSPORT_RECV => transport::sys_transport_recv(arg1, arg2, arg3),
224 SYS_TRANSPORT_CLOSE => transport::sys_transport_close(arg1),
225 SYS_TRANSPORT_INFO => transport::sys_transport_info(arg1, arg2),
226
227 SYS_PCI_ENUM => pci::sys_pci_enum(arg1, arg2, arg3),
229 SYS_PCI_CFG_READ => pci::sys_pci_cfg_read(arg1, arg2, arg3),
230 SYS_PCI_CFG_WRITE => pci::sys_pci_cfg_write(arg1, arg2, arg3, arg4),
231
232 SYS_CHAN_CREATE => chan::sys_chan_create(arg1),
234 SYS_CHAN_SEND => chan::sys_chan_send(arg1, arg2),
235 SYS_CHAN_RECV => chan::sys_chan_recv(arg1, arg2),
236 SYS_CHAN_TRY_RECV => chan::sys_chan_try_recv(arg1, arg2),
237 SYS_CHAN_CLOSE => chan::sys_chan_close(arg1),
238 SYS_MODULE_LOAD => silo::sys_module_load(arg1, arg2),
239 SYS_MODULE_UNLOAD => silo::sys_module_unload(arg1),
240 SYS_MODULE_GET_SYMBOL => silo::sys_module_get_symbol(arg1, arg2),
241 SYS_MODULE_QUERY => silo::sys_module_query(arg1, arg2),
242 SYS_OPEN => sys_open(arg1, arg2, arg3),
243 SYS_WRITE => sys_write(arg1, arg2, arg3),
244 SYS_READ => sys_read(arg1, arg2, arg3),
245 SYS_CLOSE => sys_close(arg1),
246 SYS_LSEEK => sys_lseek(arg1, arg2, arg3),
247 SYS_FSTAT => sys_fstat(arg1, arg2),
248 SYS_STAT => sys_stat(arg1, arg2, arg3),
249 SYS_ACCESS => crate::vfs::sys_access(arg1, arg2, arg3),
250 SYS_GETDENTS => sys_getdents(arg1, arg2, arg3),
251 SYS_PIPE => sys_pipe(arg1),
252 SYS_DUP => sys_dup(arg1),
253 SYS_DUP2 => sys_dup2(arg1, arg2),
254
255 SYS_CHDIR => crate::vfs::sys_chdir(arg1, arg2),
257 SYS_FCHDIR => crate::vfs::sys_fchdir(arg1 as u32),
258 SYS_GETCWD => crate::vfs::sys_getcwd(arg1, arg2),
259 SYS_IOCTL => crate::vfs::sys_ioctl(arg1 as u32, arg2, arg3),
260 SYS_UMASK => crate::vfs::sys_umask(arg1),
261 SYS_UNLINK => crate::vfs::sys_unlink(arg1, arg2),
262 SYS_RMDIR => crate::vfs::sys_rmdir(arg1, arg2),
263 SYS_MKDIR => crate::vfs::sys_mkdir(arg1, arg2, arg3),
264 SYS_RENAME => crate::vfs::sys_rename(arg1, arg2, arg3, arg4),
265 SYS_LINK => crate::vfs::sys_link(arg1, arg2, arg3, arg4),
266 SYS_SYMLINK => crate::vfs::sys_symlink(arg1, arg2, arg3, arg4),
267 SYS_READLINK => crate::vfs::sys_readlink(arg1, arg2, arg3, arg4),
268 SYS_CHMOD => crate::vfs::sys_chmod(arg1, arg2, arg3),
269 SYS_FCHMOD => crate::vfs::sys_fchmod(arg1 as u32, arg2),
270 SYS_TRUNCATE => crate::vfs::sys_truncate(arg1, arg2, arg3),
271 SYS_FTRUNCATE => crate::vfs::sys_ftruncate(arg1 as u32, arg2),
272 SYS_PREAD => crate::vfs::sys_pread(arg1 as u32, arg2, arg3, arg4),
273 SYS_PWRITE => crate::vfs::sys_pwrite(arg1 as u32, arg2, arg3, arg4),
274 SYS_POLL => super::poll::sys_poll(arg1, arg2, arg3),
275 SYS_PPOLL => super::poll::sys_poll(arg1, arg2, 0),
276
277 SYS_OPENAT => crate::vfs::sys_openat(arg1, arg2, arg3, arg4),
279 SYS_FSTATAT => crate::vfs::sys_fstatat(arg1, arg2, arg3, arg5),
280 SYS_FACCESSAT => crate::vfs::sys_faccessat(arg1, arg2, arg3, arg4, frame.r8),
281
282 SYS_NET_RECV => net::sys_net_recv(arg1, arg2),
284 SYS_NET_SEND => net::sys_net_send(arg1, arg2),
285 SYS_NET_INFO => net::sys_net_info(arg1, arg2),
286 SYS_NET_REGISTER => net::sys_net_register(),
287
288 SYS_VOLUME_READ => volume::sys_volume_read(arg1, arg2, arg3, arg4),
290 SYS_VOLUME_WRITE => volume::sys_volume_write(arg1, arg2, arg3, arg4),
291 SYS_VOLUME_INFO => volume::sys_volume_info(arg1),
292 SYS_CLOCK_GETTIME => super::time::sys_clock_gettime(arg1 as u32, arg2),
293 SYS_NANOSLEEP => super::time::sys_nanosleep(arg1, arg2),
294 SYS_CLOCK_NANOSLEEP => {
295 super::time::sys_clock_nanosleep(arg1 as u32, arg2 as i32, arg3, arg4)
296 }
297 SYS_DEBUG_LOG => debug::sys_debug_log(arg1, arg2),
298 SYS_GETRANDOM => super::random::sys_getrandom(arg1, arg2 as usize, arg3 as u32),
299 SYS_SET_ROBUST_LIST => super::robust_list::sys_set_robust_list(arg1, arg2 as usize),
300 SYS_GET_ROBUST_LIST => super::robust_list::sys_get_robust_list(arg1 as i64, arg2, arg3),
301
302 SYS_SILO_CREATE => silo::sys_silo_create(arg1),
304 SYS_SILO_CONFIG => silo::sys_silo_config(arg1, arg2),
305 SYS_SILO_ATTACH_MODULE => silo::sys_silo_attach_module(arg1, arg2),
306 SYS_SILO_START => silo::sys_silo_start(arg1),
307 SYS_SILO_STOP => silo::sys_silo_stop(arg1),
308 SYS_SILO_KILL => silo::sys_silo_kill(arg1),
309 SYS_SILO_EVENT_NEXT => silo::sys_silo_event_next(arg1),
310 SYS_SILO_SUSPEND => silo::sys_silo_suspend(arg1),
311 SYS_SILO_RESUME => silo::sys_silo_resume(arg1),
312 SYS_SILO_PLEDGE => silo::sys_silo_pledge(arg1),
313 SYS_SILO_UNVEIL => silo::sys_silo_unveil(arg1, arg2, arg3),
314 SYS_SILO_ENTER_SANDBOX => silo::sys_silo_enter_sandbox(),
315 SYS_SILO_RENAME => silo::sys_silo_rename(arg1, arg2, arg3),
316
317 SYS_ABI_VERSION => {
319 Ok(((strat9_abi::ABI_VERSION_MAJOR as u64) << 16)
320 | (strat9_abi::ABI_VERSION_MINOR as u64))
321 }
322 _ => {
323 log::warn!("Unknown syscall: {} (0x{:x})", syscall_num, syscall_num);
324 Err(SyscallError::NotImplemented)
325 }
326 };
327 match result {
330 Ok(val) => {
331 if syscall_num == SYS_PROC_FORK {
332 crate::serial_println!("[syscall] FORK returning Ok({})", val);
333 }
334 frame.rax = val;
335 }
336 Err(e) => {
337 if syscall_num == SYS_PROC_FORK {
338 crate::serial_println!("[syscall] FORK returning err");
339 }
340 frame.rax = e.to_raw();
341 }
342 }
343
344 if crate::arch::percpu::test_and_clear_signal_pending_current() {
352 crate::process::signal::deliver_pending_signal(frame);
353 }
354
355 frame.rax
356}
357
358#[no_mangle]
361pub extern "C" fn dispatch(frame: &mut SyscallFrame) -> u64 {
362 __strat9_syscall_dispatch(frame)
363}
364
365fn sys_null() -> Result<u64, SyscallError> {
371 Ok(0x57A79)
372}
373
374fn sys_handle_close(_handle: u64) -> Result<u64, SyscallError> {
376 crate::silo::enforce_cap_for_current_task(_handle)?;
377 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
378 let caps = unsafe { &mut *task.process.capabilities.get() };
379 if let Some(cap) = caps.remove(CapId::from_raw(_handle)) {
380 release_capability(&cap, Some(task.id));
381 log::trace!("syscall: HANDLE_CLOSE({})", _handle);
382 Ok(0)
383 } else {
384 Err(SyscallError::BadHandle)
385 }
386}
387
388pub(crate) fn insert_capability_with_retention(
389 caps: &mut crate::capability::CapabilityTable,
390 cap: crate::capability::Capability,
391) -> Result<CapId, SyscallError> {
392 let id = caps.insert(cap);
393 if let Some(inserted) = caps.get(id) {
394 if inserted.resource_type == ResourceType::MemoryRegion {
395 if let Err(error) =
396 crate::memory::memory_region_registry().retain_handle(inserted.resource as u64, id)
397 {
398 let _ = caps.remove(id);
399 return Err(match error {
400 crate::memory::RegionCapError::NotFound => SyscallError::BadHandle,
401 crate::memory::RegionCapError::InvalidRegion
402 | crate::memory::RegionCapError::IncompleteRegion
403 | crate::memory::RegionCapError::InvalidAddress => {
404 SyscallError::InvalidArgument
405 }
406 crate::memory::RegionCapError::PermissionDenied => {
407 SyscallError::PermissionDenied
408 }
409 crate::memory::RegionCapError::OutOfMemory => SyscallError::OutOfMemory,
410 crate::memory::RegionCapError::InconsistentState => SyscallError::IoError,
411 });
412 }
413 }
414 }
415 Ok(id)
416}
417
418fn sys_handle_duplicate(handle: u64) -> Result<u64, SyscallError> {
420 crate::silo::enforce_cap_for_current_task(handle)?;
421 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
422 let caps = unsafe { &mut *task.process.capabilities.get() };
423 let dup = caps
424 .duplicate(CapId::from_raw(handle))
425 .ok_or(SyscallError::PermissionDenied)?;
426 let id = insert_capability_with_retention(caps, dup)?;
427 Ok(id.as_u64())
428}
429
430const HANDLE_EVENT_READABLE: u64 = 1 << 0;
431const HANDLE_EVENT_WRITABLE: u64 = 1 << 1;
432
433fn poll_handle_events(handle: u64) -> Result<u64, SyscallError> {
435 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
436 let caps = unsafe { &*task.process.capabilities.get() };
437 let cap = caps
438 .get(CapId::from_raw(handle))
439 .ok_or(SyscallError::BadHandle)?;
440
441 match cap.resource_type {
442 ResourceType::Semaphore => {
443 if !cap.permissions.read {
444 return Err(SyscallError::PermissionDenied);
445 }
446 let sem = semaphore::get_semaphore(SemId::from_u64(cap.resource as u64))
447 .ok_or(SyscallError::BadHandle)?;
448 if sem.is_destroyed() {
449 return Err(SyscallError::Pipe);
450 }
451 if sem.count() > 0 {
452 Ok(HANDLE_EVENT_READABLE)
453 } else {
454 Ok(0)
455 }
456 }
457 ResourceType::IpcPort => {
458 let port = port::get_port(PortId::from_u64(cap.resource as u64))
459 .ok_or(SyscallError::BadHandle)?;
460 if port.is_destroyed() {
461 return Err(SyscallError::Pipe);
462 }
463 let mut events = 0u64;
464 if cap.permissions.read && port.has_messages() {
465 events |= HANDLE_EVENT_READABLE;
466 }
467 if cap.permissions.write && port.can_send() {
468 events |= HANDLE_EVENT_WRITABLE;
469 }
470 if events == 0 && !cap.permissions.read && !cap.permissions.write {
471 return Err(SyscallError::PermissionDenied);
472 }
473 Ok(events)
474 }
475 ResourceType::Channel => {
476 let chan = channel::get_channel(ChanId::from_u64(cap.resource as u64))
477 .ok_or(SyscallError::BadHandle)?;
478 if chan.is_destroyed() {
479 return Err(SyscallError::Pipe);
480 }
481 let mut events = 0u64;
482 if cap.permissions.read && !chan.is_empty() {
483 events |= HANDLE_EVENT_READABLE;
484 }
485 if cap.permissions.write && chan.can_send() {
486 events |= HANDLE_EVENT_WRITABLE;
487 }
488 if events == 0 && !cap.permissions.read && !cap.permissions.write {
489 return Err(SyscallError::PermissionDenied);
490 }
491 Ok(events)
492 }
493 ResourceType::SharedRing => {
494 let _ = shared_ring::get_ring(RingId::from_u64(cap.resource as u64))
495 .ok_or(SyscallError::BadHandle)?;
496 let mut events = 0u64;
497 if cap.permissions.read {
498 events |= HANDLE_EVENT_READABLE;
499 }
500 if cap.permissions.write {
501 events |= HANDLE_EVENT_WRITABLE;
502 }
503 if events == 0 {
504 return Err(SyscallError::PermissionDenied);
505 }
506 Ok(events)
507 }
508 ResourceType::IpcTransport => {
509 let tid = crate::ipc::transport::TransportId::from_u64(cap.resource as u64);
510 let endpoint = crate::syscall::transport::TRANSPORT_MANAGER
511 .get_endpoint(tid)
512 .ok_or(SyscallError::BadHandle)?;
513 let mut events = 0u64;
514 if cap.permissions.read && endpoint.has_data() {
515 events |= HANDLE_EVENT_READABLE;
516 }
517 if cap.permissions.write && endpoint.has_space() {
518 events |= HANDLE_EVENT_WRITABLE;
519 }
520 if events == 0 && !cap.permissions.read && !cap.permissions.write {
521 return Err(SyscallError::PermissionDenied);
522 }
523 Ok(events)
524 }
525 _ => Err(SyscallError::NotSupported),
526 }
527}
528
529fn sys_handle_wait(handle: u64, timeout_ns: u64) -> Result<u64, SyscallError> {
531 crate::silo::enforce_cap_for_current_task(handle)?;
532
533 let check_ready = || -> Result<u64, SyscallError> {
534 let events = poll_handle_events(handle)?;
535 if events != 0 {
536 Ok(events)
537 } else {
538 Err(SyscallError::Again)
539 }
540 };
541
542 if timeout_ns == 0 {
543 return check_ready();
544 }
545
546 let deadline = if timeout_ns == u64::MAX {
547 None
548 } else {
549 Some(crate::syscall::time::current_time_ns().saturating_add(timeout_ns))
550 };
551
552 loop {
553 if let Ok(events) = check_ready() {
554 return Ok(events);
555 }
556
557 if crate::process::has_pending_signals() {
558 return Err(SyscallError::Interrupted);
559 }
560
561 let now = crate::syscall::time::current_time_ns();
562 let wake_ns = if let Some(deadline_ns) = deadline {
563 if now >= deadline_ns {
564 return Err(SyscallError::TimedOut);
565 }
566 core::cmp::min(deadline_ns, now.saturating_add(10_000_000))
567 } else {
568 now.saturating_add(10_000_000)
569 };
570
571 if let Some(task) = current_task_clone() {
572 task.wake_deadline_ns.store(wake_ns, Ordering::Relaxed);
573 }
574 crate::process::block_current_task();
575 if let Some(task) = current_task_clone() {
576 task.wake_deadline_ns.store(0, Ordering::Relaxed);
577 }
578 }
579}
580
581fn sys_handle_grant(handle: u64, target_pid: u64) -> Result<u64, SyscallError> {
583 crate::silo::enforce_cap_for_current_task(handle)?;
584 crate::silo::enforce_silo_may_grant()?;
585 let pid = u32::try_from(target_pid).map_err(|_| SyscallError::InvalidArgument)?;
586
587 let source = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
588 let granted = {
589 let source_caps = unsafe { &*source.process.capabilities.get() };
590 let cap = source_caps
591 .get(CapId::from_raw(handle))
592 .ok_or(SyscallError::BadHandle)?;
593 if !cap.permissions.grant {
594 return Err(SyscallError::PermissionDenied);
595 }
596 let mut dup = cap.clone();
597 dup.id = CapId::new();
598 dup
599 };
600
601 let target = crate::process::get_task_by_pid(pid).ok_or(SyscallError::NotFound)?;
602 let target_caps = unsafe { &mut *target.process.capabilities.get() };
603 let new_id = insert_capability_with_retention(target_caps, granted)?;
604 Ok(new_id.as_u64())
605}
606
607fn sys_handle_revoke(handle: u64) -> Result<u64, SyscallError> {
609 crate::silo::enforce_cap_for_current_task(handle)?;
610 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
611 let caps = unsafe { &mut *task.process.capabilities.get() };
612
613 {
614 let cap = caps
615 .get(CapId::from_raw(handle))
616 .ok_or(SyscallError::BadHandle)?;
617 if !cap.permissions.revoke {
618 return Err(SyscallError::PermissionDenied);
619 }
620 }
621
622 let cap = caps
623 .remove(CapId::from_raw(handle))
624 .ok_or(SyscallError::BadHandle)?;
625 release_capability(&cap, Some(task.id));
626 Ok(0)
627}
628
629use strat9_abi::data::HandleInfo as HandleInfoAbi;
630
631fn cap_perm_bits(p: CapPermissions) -> u32 {
633 (if p.read { 1 } else { 0 })
634 | (if p.write { 1 << 1 } else { 0 })
635 | (if p.execute { 1 << 2 } else { 0 })
636 | (if p.grant { 1 << 3 } else { 0 })
637 | (if p.revoke { 1 << 4 } else { 0 })
638}
639
640fn resource_type_code(rt: ResourceType) -> u32 {
642 match rt {
643 ResourceType::MemoryRegion => 1,
644 ResourceType::IoPortRange => 2,
645 ResourceType::InterruptLine => 3,
646 ResourceType::IpcPort => 4,
647 ResourceType::Channel => 5,
648 ResourceType::SharedRing => 6,
649 ResourceType::Semaphore => 7,
650 ResourceType::Device => 8,
651 ResourceType::AddressSpace => 9,
652 ResourceType::Silo => 10,
653 ResourceType::Module => 11,
654 ResourceType::File => 12,
655 ResourceType::Nic => 13,
656 ResourceType::FileSystem => 14,
657 ResourceType::Console => 15,
658 ResourceType::Keyboard => 16,
659 ResourceType::Volume => 17,
660 ResourceType::Namespace => 18,
661 ResourceType::IpcTransport => 19,
662 }
663}
664
665fn sys_handle_info(handle: u64, out_ptr: u64) -> Result<u64, SyscallError> {
667 crate::silo::enforce_cap_for_current_task(handle)?;
668 if out_ptr == 0 {
669 return Err(SyscallError::Fault);
670 }
671 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
672 let caps = unsafe { &*task.process.capabilities.get() };
673 let cap = caps
674 .get(CapId::from_raw(handle))
675 .ok_or(SyscallError::BadHandle)?;
676
677 let info = HandleInfoAbi {
678 resource_type: resource_type_code(cap.resource_type),
679 permissions: cap_perm_bits(cap.permissions),
680 resource: cap.resource as u64,
681 };
682 let user = UserSliceWrite::new(out_ptr, core::mem::size_of::<HandleInfoAbi>())?;
683 let bytes = unsafe {
684 core::slice::from_raw_parts(
685 &info as *const HandleInfoAbi as *const u8,
686 core::mem::size_of::<HandleInfoAbi>(),
687 )
688 };
689 user.copy_from(bytes);
690 Ok(0)
691}
692
693fn sys_proc_exit(exit_code: u64) -> Result<u64, SyscallError> {
697 log::info!("syscall: PROC_EXIT(code={})", exit_code);
698
699 crate::process::scheduler::exit_current_task(exit_code as i32)
702}
703
704fn sys_proc_yield() -> Result<u64, SyscallError> {
706 crate::process::yield_task();
707 Ok(0)
708}
709
710fn sys_sigprocmask(how: i32, set_ptr: u64, oldset_ptr: u64) -> Result<u64, SyscallError> {
714 use crate::process::current_task_clone;
715
716 const SIG_BLOCK: i32 = 0;
717 const SIG_UNBLOCK: i32 = 1;
718 const SIG_SETMASK: i32 = 2;
719
720 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
721
722 let blocked = &task.blocked_signals;
723
724 if oldset_ptr != 0 {
725 let old_mask = blocked.get_mask();
726 let user = UserSliceWrite::new(oldset_ptr, 8)?;
727 user.copy_from(&old_mask.to_ne_bytes());
728 }
729
730 if set_ptr != 0 {
731 let user = UserSliceRead::new(set_ptr, 8)?;
732 let mut buf = [0u8; 8];
733 user.copy_to(&mut buf);
734 let new_mask = u64::from_ne_bytes(buf);
735
736 let old_mask = blocked.get_mask();
737 let updated_mask = match how {
738 SIG_BLOCK => old_mask | new_mask,
739 SIG_UNBLOCK => old_mask & !new_mask,
740 SIG_SETMASK => new_mask,
741 _ => return Err(SyscallError::InvalidArgument),
742 };
743
744 blocked.set_mask(updated_mask);
745 }
746
747 Ok(0)
748}
749
750fn sys_uname(uts_ptr: u64) -> Result<u64, SyscallError> {
752 const UTS_FIELD_LEN: usize = 65;
753 const UTS_TOTAL_LEN: usize = UTS_FIELD_LEN * 6;
754
755 if uts_ptr == 0 {
756 return Err(SyscallError::Fault);
757 }
758
759 fn write_field(dst: &mut [u8], src: &[u8]) {
761 let n = core::cmp::min(src.len(), dst.len().saturating_sub(1));
762 if n > 0 {
763 dst[..n].copy_from_slice(&src[..n]);
764 }
765 dst[n] = 0;
766 }
767
768 let mut uts = [0u8; UTS_TOTAL_LEN];
769 write_field(&mut uts[..UTS_FIELD_LEN], b"Strat9");
770 write_field(&mut uts[1 * UTS_FIELD_LEN..2 * UTS_FIELD_LEN], b"localhost");
771 write_field(&mut uts[2 * UTS_FIELD_LEN..3 * UTS_FIELD_LEN], b"0.1.0");
772 write_field(&mut uts[3 * UTS_FIELD_LEN..4 * UTS_FIELD_LEN], b"Strat9-OS");
773 write_field(&mut uts[4 * UTS_FIELD_LEN..5 * UTS_FIELD_LEN], b"x86_64");
774 write_field(
775 &mut uts[5 * UTS_FIELD_LEN..6 * UTS_FIELD_LEN],
776 b"localdomain",
777 );
778
779 let user = UserSliceWrite::new(uts_ptr, UTS_TOTAL_LEN)?;
780 user.copy_from(&uts);
781 Ok(0)
782}
783
784fn sys_write(fd: u64, buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
786 crate::vfs::sys_write(fd as u32, buf_ptr, buf_len)
787}
788
789fn sys_open(path_ptr: u64, path_len: u64, flags: u64) -> Result<u64, SyscallError> {
791 crate::vfs::sys_open(path_ptr, path_len, flags)
792}
793
794fn sys_read(fd: u64, buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
796 crate::vfs::sys_read(fd as u32, buf_ptr, buf_len)
797}
798
799fn sys_close(fd: u64) -> Result<u64, SyscallError> {
801 crate::vfs::sys_close(fd as u32)
802}
803
804fn sys_lseek(fd: u64, offset: u64, whence: u64) -> Result<u64, SyscallError> {
806 crate::vfs::sys_lseek(fd as u32, offset as i64, whence as u32)
807}
808
809fn sys_fstat(fd: u64, stat_ptr: u64) -> Result<u64, SyscallError> {
811 crate::vfs::sys_fstat(fd as u32, stat_ptr)
812}
813
814fn sys_stat(path_ptr: u64, path_len: u64, stat_ptr: u64) -> Result<u64, SyscallError> {
816 crate::vfs::sys_stat(path_ptr, path_len, stat_ptr)
817}
818
819fn sys_getdents(fd: u64, buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
821 crate::vfs::sys_getdents(fd as u32, buf_ptr, buf_len)
822}
823
824fn sys_pipe(fds_ptr: u64) -> Result<u64, SyscallError> {
826 crate::vfs::sys_pipe(fds_ptr)
827}
828
829fn sys_dup(old_fd: u64) -> Result<u64, SyscallError> {
831 crate::vfs::sys_dup(old_fd as u32)
832}
833
834fn sys_dup2(old_fd: u64, new_fd: u64) -> Result<u64, SyscallError> {
836 crate::vfs::sys_dup2(old_fd as u32, new_fd as u32)
837}