1use core::fmt::Display;
2
3use alloc::string::String;
4
5use crate::file::File;
6use crate::fs::FsError;
7use crate::param::NOFILE;
8use crate::proc::{Proc, TrapFrame, current_proc, current_proc_and_data_mut};
9use crate::sysfile::*;
10use crate::sysproc::*;
11use crate::vm::VA;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[repr(u16)]
19pub enum SysError {
20 NotPermitted = 1,
21 NoEntry = 2,
22 NoProcess = 3,
23 Interrupted = 4,
24 IoError = 5,
25 InvalidExecutable = 8,
26 BadDescriptor = 9,
27 NoChildren = 10,
28 ResourceUnavailable = 11,
29 OutOfMemory = 12,
30 BadAddress = 14,
31 AlreadyExists = 17,
32 CrossDeviceLink = 18,
33 NotDirectory = 20,
34 IsDirectory = 21,
35 InvalidArgument = 22,
36 FileTableFull = 23,
37 TooManyFiles = 24,
38 NoSpace = 28,
39 TooManyLinks = 31,
40 BrokenPipe = 32,
41 NameTooLong = 36,
42 NotImplemented = 38,
43 NotEmpty = 39,
44}
45
46impl SysError {
47 pub fn as_code(self) -> u16 {
49 self as u16
50 }
51
52 pub fn from_code(code: u16) -> Self {
54 match code {
55 1 => Self::NotPermitted,
56 2 => Self::NoEntry,
57 3 => Self::NoProcess,
58 4 => Self::Interrupted,
59 5 => Self::IoError,
60 8 => Self::InvalidExecutable,
61 9 => Self::BadDescriptor,
62 10 => Self::NoChildren,
63 11 => Self::ResourceUnavailable,
64 12 => Self::OutOfMemory,
65 14 => Self::BadAddress,
66 17 => Self::AlreadyExists,
67 18 => Self::CrossDeviceLink,
68 20 => Self::NotDirectory,
69 21 => Self::IsDirectory,
70 22 => Self::InvalidArgument,
71 23 => Self::FileTableFull,
72 24 => Self::TooManyFiles,
73 28 => Self::NoSpace,
74 31 => Self::TooManyLinks,
75 32 => Self::BrokenPipe,
76 36 => Self::NameTooLong,
77 38 => Self::NotImplemented,
78 39 => Self::NotEmpty,
79 _ => Self::InvalidArgument,
80 }
81 }
82}
83
84impl Display for SysError {
85 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
86 match self {
87 SysError::NotPermitted => write!(f, "operation not permitted"),
88 SysError::NoEntry => write!(f, "no such file or directory"),
89 SysError::NoProcess => write!(f, "no such process"),
90 SysError::Interrupted => write!(f, "interrupted"),
91 SysError::IoError => write!(f, "input/output error"),
92 SysError::InvalidExecutable => write!(f, "exec format error"),
93 SysError::BadDescriptor => write!(f, "bad file descriptor"),
94 SysError::NoChildren => write!(f, "no child processes"),
95 SysError::ResourceUnavailable => write!(f, "resource temporarily unavailable"),
96 SysError::OutOfMemory => write!(f, "cannot allocate memory"),
97 SysError::BadAddress => write!(f, "bad address"),
98 SysError::AlreadyExists => write!(f, "file exists"),
99 SysError::CrossDeviceLink => write!(f, "cross-device link"),
100 SysError::NotDirectory => write!(f, "not a directory"),
101 SysError::IsDirectory => write!(f, "is a directory"),
102 SysError::InvalidArgument => write!(f, "invalid argument"),
103 SysError::FileTableFull => write!(f, "too many open files in system"),
104 SysError::TooManyFiles => write!(f, "too many open files"),
105 SysError::NoSpace => write!(f, "no space left on device"),
106 SysError::TooManyLinks => write!(f, "too many links"),
107 SysError::BrokenPipe => write!(f, "broken pipe"),
108 SysError::NameTooLong => write!(f, "file name too long"),
109 SysError::NotImplemented => write!(f, "function not implemented"),
110 SysError::NotEmpty => write!(f, "directory not empty"),
111 }
112 }
113}
114
115impl From<FsError> for SysError {
116 fn from(e: FsError) -> Self {
117 match e {
118 FsError::OutOfBlock | FsError::OutOfInode => SysError::NoSpace,
119 FsError::OutOfFile | FsError::OutOfPipe => SysError::FileTableFull,
120 FsError::OutOfRange => SysError::InvalidArgument,
121 FsError::Read | FsError::Write => SysError::IoError,
122 FsError::Create => SysError::NoSpace,
123 FsError::Link => SysError::AlreadyExists,
124 FsError::Resolve => SysError::NoEntry,
125 FsError::Type => SysError::InvalidArgument,
126 FsError::Copy => SysError::BadAddress,
127 }
128 }
129}
130
131pub struct SyscallArgs<'a> {
133 trapframe: &'a TrapFrame,
134 proc: &'static Proc,
135}
136
137impl<'a> SyscallArgs<'a> {
138 fn new(trapframe: &'a TrapFrame, proc: &'static Proc) -> Self {
140 Self { trapframe, proc }
141 }
142
143 pub fn proc(&self) -> &Proc {
144 self.proc
145 }
146
147 pub fn get_raw(&self, index: usize) -> usize {
149 match index {
150 0 => self.trapframe.a0,
151 1 => self.trapframe.a1,
152 2 => self.trapframe.a2,
153 3 => self.trapframe.a3,
154 4 => self.trapframe.a4,
155 5 => self.trapframe.a5,
156 _ => panic!("invalid syscall argument index {}", index),
157 }
158 }
159
160 pub fn get_int(&self, index: usize) -> isize {
162 self.get_raw(index) as isize
163 }
164
165 pub fn get_addr(&self, index: usize) -> VA {
169 VA::from(self.get_raw(index))
170 }
171
172 pub fn get_file(&self, index: usize) -> Result<(usize, File), SysError> {
175 let fd: usize = try_log!(
176 self.get_int(index)
177 .try_into()
178 .or(Err(SysError::BadDescriptor))
179 );
180
181 if fd >= NOFILE {
182 err!(SysError::BadDescriptor);
183 }
184
185 if let Some(file) = ¤t_proc().data().open_files[fd] {
186 return Ok((fd, file.clone()));
187 }
188
189 err!(SysError::BadDescriptor);
190 }
191
192 pub fn fetch_string(&self, addr: VA, max: usize) -> Result<String, SysError> {
194 let (_proc, data) = current_proc_and_data_mut();
195
196 let mut result = String::with_capacity(max);
197
198 let mut buf = [0u8; 1];
199 for i in 0..max {
200 try_log!(
201 data.pagetable_mut()
202 .copy_from(VA::from(addr.as_usize() + i), &mut buf)
203 .map_err(|_| SysError::BadAddress)
204 );
205
206 if buf[0] == 0 {
207 return Ok(result);
208 }
209
210 result.push(buf[0] as char);
211 }
212
213 Ok(result)
214 }
215}
216
217#[repr(usize)]
219#[derive(Debug, Clone, Copy, PartialEq, Eq)]
220pub enum Syscall {
221 Fork = 1,
222 Exit = 2,
223 Wait = 3,
224 Pipe = 4,
225 Read = 5,
226 Kill = 6,
227 Exec = 7,
228 Fstat = 8,
229 Chdir = 9,
230 Dup = 10,
231 Getpid = 11,
232 Sbrk = 12,
233 Sleep = 13,
234 Uptime = 14,
235 Open = 15,
236 Write = 16,
237 Mknod = 17,
238 Unlink = 18,
239 Link = 19,
240 Mkdir = 20,
241 Close = 21,
242}
243
244impl TryFrom<usize> for Syscall {
245 type Error = SysError;
246
247 fn try_from(value: usize) -> Result<Self, Self::Error> {
248 match value {
249 1 => Ok(Syscall::Fork),
250 2 => Ok(Syscall::Exit),
251 3 => Ok(Syscall::Wait),
252 4 => Ok(Syscall::Pipe),
253 5 => Ok(Syscall::Read),
254 6 => Ok(Syscall::Kill),
255 7 => Ok(Syscall::Exec),
256 8 => Ok(Syscall::Fstat),
257 9 => Ok(Syscall::Chdir),
258 10 => Ok(Syscall::Dup),
259 11 => Ok(Syscall::Getpid),
260 12 => Ok(Syscall::Sbrk),
261 13 => Ok(Syscall::Sleep),
262 14 => Ok(Syscall::Uptime),
263 15 => Ok(Syscall::Open),
264 16 => Ok(Syscall::Write),
265 17 => Ok(Syscall::Mknod),
266 18 => Ok(Syscall::Unlink),
267 19 => Ok(Syscall::Link),
268 20 => Ok(Syscall::Mkdir),
269 21 => Ok(Syscall::Close),
270 _ => Err(SysError::NotImplemented),
271 }
272 }
273}
274
275#[unsafe(no_mangle)]
280pub unsafe fn syscall(trapframe: &mut TrapFrame) {
281 let proc = current_proc();
282 let args = SyscallArgs::new(trapframe, proc);
283
284 let result = match Syscall::try_from(trapframe.a7) {
293 Ok(syscall) => match syscall {
294 Syscall::Fork => sys_fork(&args),
295 Syscall::Exit => sys_exit(&args),
296 Syscall::Wait => sys_wait(&args),
297 Syscall::Pipe => sys_pipe(&args),
298 Syscall::Read => sys_read(&args),
299 Syscall::Kill => sys_kill(&args),
300 Syscall::Exec => sys_exec(&args),
301 Syscall::Fstat => sys_fstat(&args),
302 Syscall::Chdir => sys_chdir(&args),
303 Syscall::Dup => sys_dup(&args),
304 Syscall::Getpid => sys_getpid(&args),
305 Syscall::Sbrk => sys_sbrk(&args),
306 Syscall::Sleep => sys_sleep(&args),
307 Syscall::Uptime => sys_uptime(&args),
308 Syscall::Open => sys_open(&args),
309 Syscall::Write => sys_write(&args),
310 Syscall::Mknod => sys_mknod(&args),
311 Syscall::Unlink => sys_unlink(&args),
312 Syscall::Link => sys_link(&args),
313 Syscall::Mkdir => sys_mkdir(&args),
314 Syscall::Close => sys_close(&args),
315 },
316 Err(e) => Err(e),
317 };
318
319 trapframe.a0 = match log!(result) {
320 Ok(v) => v,
321 Err(error) => {
322 #[cfg(debug_assertions)]
323 println!(
324 "! syscall error ({}) from proc {} ({})",
325 error,
326 *proc.inner.lock().pid,
327 proc.data().name,
328 );
329 (-(error.as_code() as isize)) as usize
330 }
331 };
332
333 }