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