Skip to main content

strat9_kernel/syscall/
ipc_ring.rs

1//! IPC ring-buffer syscall handlers.
2//!
3//! Provides shared-memory ring buffers for zero-copy IPC between processes.
4
5use super::error::SyscallError;
6use crate::{
7    capability::{get_capability_manager, CapId, CapPermissions, ResourceType},
8    ipc::shared_ring::{self, RingId},
9    memory::UserSliceWrite,
10    process::current_task_clone,
11};
12
13/// SYS_IPC_RING_CREATE: allocate a shared-memory ring buffer.
14pub fn sys_ipc_ring_create(size: u64) -> Result<u64, SyscallError> {
15    let sz = usize::try_from(size).map_err(|_| SyscallError::InvalidArgument)?;
16    let ring_id = shared_ring::create_ring(sz).map_err(|e| match e {
17        shared_ring::RingError::InvalidSize => SyscallError::InvalidArgument,
18        shared_ring::RingError::Alloc => SyscallError::OutOfMemory,
19        shared_ring::RingError::NotFound => SyscallError::NotFound,
20    })?;
21
22    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
23    let cap = get_capability_manager().create_capability(
24        ResourceType::SharedRing,
25        ring_id.as_u64() as usize,
26        CapPermissions {
27            read: true,
28            write: true,
29            execute: false,
30            grant: true,
31            revoke: true,
32        },
33    );
34    let cap_id = unsafe { (&mut *task.process.capabilities.get()).insert(cap) };
35    Ok(cap_id.as_u64())
36}
37
38/// SYS_IPC_RING_MAP: map a shared ring buffer into the caller's address space.
39pub fn sys_ipc_ring_map(ring_handle: u64, out_ptr: u64) -> Result<u64, SyscallError> {
40    crate::silo::enforce_cap_for_current_task(ring_handle)?;
41    if out_ptr == 0 {
42        return Err(SyscallError::Fault);
43    }
44
45    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
46    let caps = unsafe { &*task.process.capabilities.get() };
47    let required = CapPermissions {
48        read: true,
49        write: true,
50        execute: false,
51        grant: false,
52        revoke: false,
53    };
54    let cap = caps
55        .get_with_permissions(CapId::from_raw(ring_handle), required)
56        .ok_or(SyscallError::PermissionDenied)?;
57    if cap.resource_type != ResourceType::SharedRing {
58        return Err(SyscallError::BadHandle);
59    }
60
61    let ring_id = RingId::from_u64(cap.resource as u64);
62    let ring_obj = shared_ring::get_ring(ring_id).ok_or(SyscallError::BadHandle)?;
63    let frame_phys_addrs = ring_obj.frame_phys_addrs();
64    let mapping_cap_ids = ring_obj.mapping_cap_ids().to_vec();
65    let page_count = ring_obj.page_count();
66    let map_size = page_count
67        .checked_mul(4096)
68        .ok_or(SyscallError::InvalidArgument)? as u64;
69
70    let addr_space = task.process.address_space_arc();
71    let base = addr_space
72        .find_free_vma_range(
73            super::mmap::MMAP_BASE,
74            page_count,
75            crate::memory::address_space::VmaPageSize::Small,
76        )
77        .ok_or(SyscallError::OutOfMemory)?;
78
79    addr_space
80        .map_shared_frames_with_cap_ids(
81            base,
82            &frame_phys_addrs,
83            Some(&mapping_cap_ids),
84            crate::memory::address_space::VmaFlags {
85                readable: true,
86                writable: true,
87                executable: false,
88                user_accessible: true,
89            },
90            crate::memory::address_space::VmaType::Anonymous,
91        )
92        .map_err(|_| SyscallError::OutOfMemory)?;
93
94    let out = UserSliceWrite::new(out_ptr, core::mem::size_of::<u64>())?;
95    out.copy_from(&base.to_ne_bytes());
96    Ok(map_size)
97}