emerald_std/
io.rs

1use core::ffi::CStr;
2
3pub use kernel_user_link::file::BlockingMode;
4pub use kernel_user_link::file::DirEntry;
5pub use kernel_user_link::file::DirFilename;
6pub use kernel_user_link::file::FileMeta;
7pub use kernel_user_link::file::FileStat;
8pub use kernel_user_link::file::FileType;
9pub use kernel_user_link::file::OpenOptions;
10pub use kernel_user_link::file::SeekFrom;
11pub use kernel_user_link::file::SeekWhence;
12pub use kernel_user_link::file::MAX_FILENAME_LEN;
13pub use kernel_user_link::FD_STDERR;
14pub use kernel_user_link::FD_STDIN;
15pub use kernel_user_link::FD_STDOUT;
16
17use kernel_user_link::call_syscall;
18use kernel_user_link::syscalls::SyscallError;
19use kernel_user_link::syscalls::SYS_CHDIR;
20use kernel_user_link::syscalls::SYS_CLOSE;
21use kernel_user_link::syscalls::SYS_CREATE_PIPE;
22use kernel_user_link::syscalls::SYS_GET_CWD;
23use kernel_user_link::syscalls::SYS_GET_FILE_META;
24use kernel_user_link::syscalls::SYS_OPEN;
25use kernel_user_link::syscalls::SYS_OPEN_DIR;
26use kernel_user_link::syscalls::SYS_READ;
27use kernel_user_link::syscalls::SYS_READ_DIR;
28use kernel_user_link::syscalls::SYS_SEEK;
29use kernel_user_link::syscalls::SYS_SET_FILE_META;
30use kernel_user_link::syscalls::SYS_STAT;
31use kernel_user_link::syscalls::SYS_WRITE;
32
33/// # Safety
34/// This function assumes that `fd` is a valid file descriptor.
35/// And that `buf` is a valid buffer.
36pub unsafe fn syscall_read(fd: usize, buf: &mut [u8]) -> Result<u64, SyscallError> {
37    unsafe {
38        call_syscall!(
39            SYS_READ,
40            fd,                      // fd
41            buf.as_mut_ptr() as u64, // buf
42            buf.len() as u64         // size
43        )
44    }
45}
46
47/// # Safety
48/// This function assumes that `fd` is a valid file descriptor.
49/// And that `buf` is a valid buffer.
50pub unsafe fn syscall_write(fd: usize, buf: &[u8]) -> Result<u64, SyscallError> {
51    unsafe {
52        call_syscall!(
53            SYS_WRITE,
54            fd,                  // fd
55            buf.as_ptr() as u64, // buf
56            buf.len() as u64     // size
57        )
58    }
59}
60
61/// # Safety
62/// This function assumes that `path` is a valid C string.
63/// And that `flags` are valid.
64pub unsafe fn syscall_open(
65    path: &CStr,
66    open_options: OpenOptions,
67    flags: usize,
68) -> Result<usize, SyscallError> {
69    unsafe {
70        call_syscall!(
71            SYS_OPEN,
72            path.as_ptr() as u64,  // path
73            open_options.to_u64(), // open_options
74            flags as u64           // flags
75        )
76        .map(|fd| fd as usize)
77    }
78}
79
80/// # Safety
81/// This function assumes that `fd` is a valid file descriptor.
82pub unsafe fn syscall_close(fd: usize) -> Result<(), SyscallError> {
83    unsafe {
84        call_syscall!(
85            SYS_CLOSE,
86            fd,                  // fd
87        )
88        .map(|e| assert!(e == 0))
89    }
90}
91
92/// # Safety
93/// This function creates a pipe and return the descriptors.
94/// Callers must ensure to use the descriptors correctly.
95pub unsafe fn syscall_create_pipe() -> Result<(usize, usize), SyscallError> {
96    let mut in_fd: u64 = 0;
97    let mut out_fd: u64 = 0;
98    unsafe {
99        call_syscall!(
100            SYS_CREATE_PIPE,
101            &mut in_fd as *mut u64 as u64,  // in_fd
102            &mut out_fd as *mut u64 as u64  // out_fd
103        )?
104    };
105
106    Ok((in_fd as usize, out_fd as usize))
107}
108
109/// # Safety
110/// This function assumes that `fd` is a valid file descriptor.
111#[deprecated(note = "Use `syscall_set_file_meta` instead")]
112pub unsafe fn syscall_blocking_mode(
113    fd: usize,
114    blocking_mode: BlockingMode,
115) -> Result<(), SyscallError> {
116    syscall_set_file_meta(fd, FileMeta::BlockingMode(blocking_mode))
117}
118
119/// # Safety
120/// This function assumes that `path` is a valid C string.
121/// Also assume `stat` is a valid pointer to a valid `FileStat` struct.
122pub unsafe fn syscall_stat(path: &CStr, stat: &mut FileStat) -> Result<(), SyscallError> {
123    let stat_ptr = stat as *mut FileStat as u64;
124    unsafe {
125        call_syscall!(
126            SYS_STAT,
127            path.as_ptr() as u64, // path
128            stat_ptr              // stat_ptr
129        )
130        .map(|e| assert!(e == 0))
131    }
132}
133
134/// # Safety
135/// This function assumes that `path` is a valid C string.
136pub unsafe fn syscall_open_dir(path: &CStr) -> Result<usize, SyscallError> {
137    unsafe {
138        call_syscall!(
139            SYS_OPEN_DIR,
140            path.as_ptr() as u64, // path
141        )
142        .map(|fd| fd as usize)
143    }
144}
145
146/// # Safety
147/// This function assumes that `fd` is a valid file descriptor.
148/// Also assume `entry` is a valid pointer to a valid `DirEntry` struct.
149pub unsafe fn syscall_read_dir(fd: usize, entries: &mut [DirEntry]) -> Result<usize, SyscallError> {
150    let entries_ptr = entries.as_mut_ptr() as u64;
151    unsafe {
152        call_syscall!(
153            SYS_READ_DIR,
154            fd,                   // fd
155            entries_ptr,          // entries_ptr
156            entries.len() as u64  // len
157        )
158        .map(|written| written as usize)
159    }
160}
161
162/// # Safety
163/// This function assumes that `path` is a valid C string.
164pub unsafe fn syscall_chdir(path: &CStr) -> Result<(), SyscallError> {
165    unsafe {
166        call_syscall!(
167            SYS_CHDIR,
168            path.as_ptr() as u64, // path
169        )
170        .map(|e| assert!(e == 0))
171    }
172}
173
174/// # Safety
175/// This function assumes that `path` is a valid buffer.
176/// The result will be a string written in the buffer, NULL won't be written, but the written length will be returned
177pub unsafe fn syscall_get_cwd(path: &mut [u8]) -> Result<usize, SyscallError> {
178    unsafe {
179        call_syscall!(
180            SYS_GET_CWD,
181            path.as_mut_ptr() as u64, // path buffer
182            path.len() as u64         // len
183        )
184        .map(|written| written as usize)
185    }
186}
187
188/// # Safety
189/// This function assumes that `fd` is a valid file descriptor.
190pub unsafe fn syscall_set_file_meta(fd: usize, meta: FileMeta) -> Result<(), SyscallError> {
191    let meta_id = meta.to_u64_meta_id();
192    let meta_data = meta.inner_u64();
193    unsafe {
194        call_syscall!(
195            SYS_SET_FILE_META,
196            fd,        // fd
197            meta_id,   // meta_id
198            meta_data  // meta_data
199        )
200        .map(|e| assert!(e == 0))
201    }
202}
203
204/// # Safety
205/// This function assumes that `fd` is a valid file descriptor.
206///
207/// The data in `meta` will be ignored, only the `type` is important here
208pub unsafe fn syscall_get_file_meta(fd: usize, meta: &mut FileMeta) -> Result<(), SyscallError> {
209    let meta_id = meta.to_u64_meta_id();
210    let mut meta_data = 0;
211    unsafe {
212        call_syscall!(
213            SYS_GET_FILE_META,
214            fd,                                // fd
215            meta_id,                           // meta_id
216            &mut meta_data as *mut u64 as u64  // meta_data
217        )
218        .map(|e| assert!(e == 0))
219    }?;
220    // this should never fail, as the syscall would return an error if anything is wrong, `meta_data`
221    // should be valid and correct at this stage
222    *meta = FileMeta::try_from((meta_id, meta_data)).unwrap();
223
224    Ok(())
225}
226
227/// # Safety
228/// This function assumes that `fd` is a valid file descriptor.
229pub unsafe fn syscall_seek(fd: usize, seek: SeekFrom) -> Result<u64, SyscallError> {
230    unsafe {
231        call_syscall!(
232            SYS_SEEK,
233            fd,                 // fd
234            seek.whence as u64, // whence
235            seek.offset as u64, // offset
236        )
237    }
238}