Skip to main content

syscall/
call.rs

1use super::{
2    arch::*,
3    data::{Map, Stat, StatVfs, StdFsCallMeta, TimeSpec},
4    error::Result,
5    flag::*,
6    number::*,
7};
8
9use core::mem;
10
11/// Close a file
12pub fn close(fd: usize) -> Result<usize> {
13    unsafe { syscall1(SYS_CLOSE, fd) }
14}
15
16/// Get the current system time
17pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> {
18    unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) }
19}
20
21/// Copy and transform a file descriptor
22pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
23    unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) }
24}
25
26/// Copy and transform a file descriptor
27pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> {
28    unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) }
29}
30
31/// Change file permissions
32pub fn fchmod(fd: usize, mode: u16) -> Result<usize> {
33    unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) }
34}
35
36/// Change file ownership
37pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result<usize> {
38    unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) }
39}
40
41/// Change file descriptor flags
42pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
43    unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) }
44}
45
46/// Map a file into memory, but with the ability to set the address to map into, either as a hint
47/// or as a requirement of the map.
48///
49/// # Errors
50/// `EACCES` - the file descriptor was not open for reading
51/// `EBADF` - if the file descriptor was invalid
52/// `ENODEV` - mmapping was not supported
53/// `EINVAL` - invalid combination of flags
54/// `EEXIST` - if [`MapFlags::MAP_FIXED`] was set, and the address specified was already in use.
55///
56pub unsafe fn fmap(fd: usize, map: &Map) -> Result<usize> {
57    syscall3(
58        SYS_FMAP,
59        fd,
60        map as *const Map as usize,
61        mem::size_of::<Map>(),
62    )
63}
64
65/// Unmap whole (or partial) continous memory-mapped files
66pub unsafe fn funmap(addr: usize, len: usize) -> Result<usize> {
67    syscall2(SYS_FUNMAP, addr, len)
68}
69
70/// Retrieve the canonical path of a file
71pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> {
72    unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) }
73}
74
75/// Create a link to a file
76pub fn flink<T: AsRef<str>>(fd: usize, path: T) -> Result<usize> {
77    let path = path.as_ref();
78    unsafe { syscall3(SYS_FLINK, fd, path.as_ptr() as usize, path.len()) }
79}
80
81/// Rename a file
82pub fn frename<T: AsRef<str>>(fd: usize, path: T) -> Result<usize> {
83    let path = path.as_ref();
84    unsafe { syscall3(SYS_FRENAME, fd, path.as_ptr() as usize, path.len()) }
85}
86
87/// Get metadata about a file
88pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> {
89    unsafe {
90        syscall3(
91            SYS_FSTAT,
92            fd,
93            stat as *mut Stat as usize,
94            mem::size_of::<Stat>(),
95        )
96    }
97}
98
99/// Get metadata about a filesystem
100pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result<usize> {
101    unsafe {
102        syscall3(
103            SYS_FSTATVFS,
104            fd,
105            stat as *mut StatVfs as usize,
106            mem::size_of::<StatVfs>(),
107        )
108    }
109}
110
111/// Sync a file descriptor to its underlying medium
112pub fn fsync(fd: usize) -> Result<usize> {
113    unsafe { syscall1(SYS_FSYNC, fd) }
114}
115
116/// Truncate or extend a file to a specified length
117pub fn ftruncate(fd: usize, len: usize) -> Result<usize> {
118    unsafe { syscall2(SYS_FTRUNCATE, fd, len) }
119}
120
121// Change modify and/or access times
122pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result<usize> {
123    unsafe {
124        syscall3(
125            SYS_FUTIMENS,
126            fd,
127            times.as_ptr() as usize,
128            mem::size_of_val(times),
129        )
130    }
131}
132
133/// Fast userspace mutex
134pub unsafe fn futex(
135    addr: *mut i32,
136    op: usize,
137    val: i32,
138    val2: usize,
139    addr2: *mut i32,
140) -> Result<usize> {
141    syscall5(
142        SYS_FUTEX,
143        addr as usize,
144        op,
145        (val as isize) as usize,
146        val2,
147        addr2 as usize,
148    )
149}
150
151/// Seek to `offset` bytes in a file descriptor
152pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result<usize> {
153    unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) }
154}
155
156/// Make a new scheme namespace
157pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> {
158    unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) }
159}
160
161/// Change mapping flags
162pub unsafe fn mprotect(addr: usize, size: usize, flags: MapFlags) -> Result<usize> {
163    syscall3(SYS_MPROTECT, addr, size, flags.bits())
164}
165
166/// Sleep for the time specified in `req`
167pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> {
168    unsafe {
169        syscall2(
170            SYS_NANOSLEEP,
171            req as *const TimeSpec as usize,
172            rem as *mut TimeSpec as usize,
173        )
174    }
175}
176
177/// Open a file at a specific path
178pub fn openat<T: AsRef<str>>(
179    fd: usize,
180    path: T,
181    flags: usize,
182    fcntl_flags: usize,
183) -> Result<usize> {
184    let path = path.as_ref();
185    unsafe {
186        syscall5(
187            SYS_OPENAT,
188            fd,
189            path.as_ptr() as usize,
190            path.len(),
191            flags,
192            fcntl_flags,
193        )
194    }
195}
196/// Open a file at a specific path with filter
197pub fn openat_with_filter<T: AsRef<str>>(
198    fd: usize,
199    path: T,
200    flags: usize,
201    fcntl_flags: usize,
202    euid: u32,
203    egid: u32,
204) -> Result<usize> {
205    let path = path.as_ref();
206    unsafe {
207        syscall6(
208            SYS_OPENAT_WITH_FILTER,
209            fd,
210            path.as_ptr() as usize,
211            path.len(),
212            flags | fcntl_flags,
213            // NOTE: Short-term solution to allow namespace management.
214            // In the long term, we need to figure out how we should best handle
215            // Unix permissions using capabilities.
216            euid as usize,
217            egid as usize,
218        )
219    }
220}
221
222/// Remove a file at at specific path
223pub fn unlinkat<T: AsRef<str>>(fd: usize, path: T, flags: usize) -> Result<usize> {
224    let path = path.as_ref();
225    unsafe { syscall4(SYS_UNLINKAT, fd, path.as_ptr() as usize, path.len(), flags) }
226}
227/// Remove a file at at specific path with filter
228pub fn unlinkat_with_filter<T: AsRef<str>>(
229    fd: usize,
230    path: T,
231    flags: usize,
232    euid: u32,
233    egid: u32,
234) -> Result<usize> {
235    let path = path.as_ref();
236    unsafe {
237        syscall6(
238            SYS_UNLINKAT_WITH_FILTER,
239            fd,
240            path.as_ptr() as usize,
241            path.len(),
242            flags,
243            // NOTE: Short-term solution to allow namespace management.
244            // In the long term, we need to figure out how we should best handle
245            // Unix permissions using capabilities.
246            euid as usize,
247            egid as usize,
248        )
249    }
250}
251
252/// Read from a file descriptor into a buffer
253pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
254    unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) }
255}
256
257/// Write a buffer to a file descriptor
258///
259/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning
260/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which
261/// were written.
262///
263/// # Errors
264///
265/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block
266/// * `EBADF` - the file descriptor is not valid or is not open for writing
267/// * `EFAULT` - `buf` does not point to the process's addressible memory
268/// * `EIO` - an I/O error occurred
269/// * `ENOSPC` - the device containing the file descriptor has no room for data
270/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed
271pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
272    unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) }
273}
274
275/// Yield the process's time slice to the kernel
276///
277/// This function will return Ok(0) on success
278pub fn sched_yield() -> Result<usize> {
279    unsafe { syscall0(SYS_YIELD) }
280}
281
282/// Send a file descriptor `fd`, handled by the scheme providing `receiver_socket`. `flags` is
283/// currently unused (must be zero), and `arg` is included in the scheme call.
284///
285/// The scheme can return an arbitrary value.
286pub fn sendfd(receiver_socket: usize, fd: usize, flags: usize, arg: u64) -> Result<usize> {
287    #[cfg(target_pointer_width = "32")]
288    unsafe {
289        syscall5(
290            SYS_SENDFD,
291            receiver_socket,
292            fd,
293            flags,
294            arg as u32 as usize,
295            (arg >> 32) as u32 as usize,
296        )
297    }
298
299    #[cfg(target_pointer_width = "64")]
300    unsafe {
301        syscall4(SYS_SENDFD, receiver_socket, fd, flags, arg as usize)
302    }
303}
304
305pub trait Call {
306    unsafe fn raw_call(
307        &self,
308        payload_ptr: *const u8,
309        len: usize,
310        flags: CallFlags,
311        metadata: &[u64],
312    ) -> Result<usize>;
313}
314
315impl Call for usize {
316    unsafe fn raw_call(
317        &self,
318        payload_ptr: *const u8,
319        len: usize,
320        flags: CallFlags,
321        metadata: &[u64],
322    ) -> Result<usize> {
323        unsafe {
324            syscall5(
325                SYS_CALL,
326                *self,
327                payload_ptr as usize,
328                len,
329                metadata.len() | flags.bits(),
330                metadata.as_ptr() as usize,
331            )
332        }
333    }
334}
335
336impl Call for &[usize] {
337    unsafe fn raw_call(
338        &self,
339        payload_ptr: *const u8,
340        len: usize,
341        flags: CallFlags,
342        metadata: &[u64],
343    ) -> Result<usize> {
344        let combined_flags = flags | CallFlags::MULTIPLE_FDS;
345        unsafe {
346            syscall6(
347                SYS_CALL,
348                self.as_ptr() as usize,
349                payload_ptr as usize,
350                len,
351                metadata.len() | combined_flags.bits(),
352                metadata.as_ptr() as usize,
353                self.len() * mem::size_of::<usize>(),
354            )
355        }
356    }
357}
358
359/// SYS_CALL interface, read-only variant
360pub fn call_ro<T: Call>(
361    fd: T,
362    payload: &mut [u8],
363    flags: CallFlags,
364    metadata: &[u64],
365) -> Result<usize> {
366    unsafe {
367        fd.raw_call(
368            payload.as_mut_ptr(),
369            payload.len(),
370            flags | CallFlags::READ,
371            metadata,
372        )
373    }
374}
375/// SYS_CALL interface, write-only variant
376pub fn call_wo<T: Call>(
377    fd: T,
378    payload: &[u8],
379    flags: CallFlags,
380    metadata: &[u64],
381) -> Result<usize> {
382    unsafe {
383        fd.raw_call(
384            payload.as_ptr(),
385            payload.len(),
386            flags | CallFlags::WRITE,
387            metadata,
388        )
389    }
390}
391/// SYS_CALL interface, read-write variant
392pub fn call_rw<T: Call>(
393    fd: T,
394    payload: &mut [u8],
395    flags: CallFlags,
396    metadata: &[u64],
397) -> Result<usize> {
398    unsafe {
399        fd.raw_call(
400            payload.as_mut_ptr(),
401            payload.len(),
402            flags | CallFlags::READ | CallFlags::WRITE,
403            metadata,
404        )
405    }
406}
407
408pub fn std_fs_call<T: Call>(fd: T, payload: &mut [u8], metadata: &StdFsCallMeta) -> Result<usize> {
409    call_rw(fd, payload, CallFlags::STD_FS, metadata)
410}