1mod types_conversions;
2
3pub const SYSCALL_INTERRUPT_NUMBER: u8 = 0xFE;
8
9pub const NUM_SYSCALLS: usize = 22;
10
11mod numbers {
12 pub const SYS_OPEN: u64 = 0;
13 pub const SYS_WRITE: u64 = 1;
14 pub const SYS_READ: u64 = 2;
15 pub const SYS_CLOSE: u64 = 3;
16 #[deprecated(note = "Use SYS_SET_FILE_META instead")]
17 pub const SYS_BLOCKING_MODE: u64 = 4;
18 pub const SYS_EXIT: u64 = 5;
19 pub const SYS_SPAWN: u64 = 6;
20 pub const SYS_INC_HEAP: u64 = 7;
21 pub const SYS_CREATE_PIPE: u64 = 8;
22 pub const SYS_WAIT_PID: u64 = 9;
23 pub const SYS_STAT: u64 = 10;
24 pub const SYS_OPEN_DIR: u64 = 11;
25 pub const SYS_READ_DIR: u64 = 12;
26 pub const SYS_GET_CWD: u64 = 13;
27 pub const SYS_CHDIR: u64 = 14;
28 pub const SYS_SET_FILE_META: u64 = 15;
29 pub const SYS_GET_FILE_META: u64 = 16;
30 pub const SYS_SLEEP: u64 = 17;
31 pub const SYS_GET_TIME: u64 = 18;
32 pub const SYS_GRAPHICS: u64 = 19;
33 pub const SYS_SEEK: u64 = 20;
34 pub const SYS_PRIORITY: u64 = 21;
35}
36pub use numbers::*;
37
38#[macro_export]
41macro_rules! call_syscall {
42 ($syscall_num:expr $(,)?) => {
43 call_syscall!(@step $syscall_num; { }; { })
44 };
45 ($syscall_num:expr, $($args:expr),* $(,)?) => {
46 call_syscall!(@step $syscall_num; { }; {$($args),*})
47 };
48 (@step $syscall_num: expr; {$($generated:tt)*}; {}) => {
49 call_syscall!(@final $syscall_num, {$($generated)*})
50 };
51 (@step $syscall_num: expr; {$($generated:tt)*}; {$one:expr}) => {
52 call_syscall!(@step $syscall_num; {in("rcx") $one, $($generated)*}; {})
53 };
54 (@step $syscall_num: expr; {$($generated:tt)*}; {$one:expr, $two:expr}) => {
55 call_syscall!(@step $syscall_num; {in("rdx") $two, $($generated)*}; {$one})
56 };
57 (@step $syscall_num: expr; {$($generated:tt)*}; {$one:expr, $two:expr, $three:expr}) => {
58 call_syscall!(@step $syscall_num; {in("rsi") $three, $($generated)*}; {$one, $two})
59 };
60 (@step $syscall_num: expr; {$($generated:tt)*}; {$one:expr, $two:expr, $three:expr, $four:expr}) => {
61 call_syscall!(@step $syscall_num; {in("rdi") $four, $($generated)*}; {$one, $two, $three})
62 };
63 (@step $syscall_num: expr; {$($generated:tt)*}; {$one:expr, $two:expr, $three:expr, $four:expr, $five:expr}) => {
64 call_syscall!(@step $syscall_num; {in("r8") $five, $($generated)*}; {$one, $two, $three, $four})
65 };
66 (@step $syscall_num: expr; {$($generated:tt)*}; {$one:expr, $two:expr, $three:expr, $four:expr, $five:expr, $six:expr}) => {
67 call_syscall!(@step $syscall_num; {in("r9") $six, $($generated)*}; {$one, $two, $three, $four, $five})
68 };
69 (@step $syscall_num: expr; {$($generated:tt)*}; {$one:expr, $two:expr, $three:expr, $four:expr, $five:expr, $six:expr, $seven:expr}) => {
70 call_syscall!(@step $syscall_num; {in("r10") $seven, $($generated)*}; {$one, $two, $three, $four, $five, $six})
71 };
72 (@step $syscall_num: expr; {$($generated:tt)*}; {$($args:expr),*}) => {
73 compile_error!("Too many arguments for syscall")
74 };
75 (@final $syscall_num: expr, {$($generated:tt)*}) => {
76 {
77 let result: u64;
78 ::core::arch::asm!("int 0xFE",
79 inout("rax") $syscall_num => result,
80 $($generated)*
81 options(nomem, nostack, preserves_flags));
82 $crate::syscalls::syscall_result_from_u64(result)
83 }
84 };
85}
86
87#[macro_export]
90macro_rules! sys_arg {
91 ($num:tt, $context_struct:expr) => {
92 sys_arg!(@impl $num, $context_struct => u64)
93 };
94 ($num:tt, $context_struct:expr => $func:ident($ty:ty)) => {
95 sys_arg!($num, $context_struct => $ty).and_then($func)
96 };
97 ($num:tt, $context_struct:expr => $ty:ty) => {
98 syscall_arg_to_u64::<$ty>(sys_arg!(@impl $num, $context_struct))
99 };
100 (@impl 0, $context_struct:expr) => {
101 $context_struct.rcx
102 };
103 (@impl 1, $context_struct:expr) => {
104 $context_struct.rdx
105 };
106 (@impl 2, $context_struct:expr) => {
107 $context_struct.rsi
108 };
109 (@impl 3, $context_struct:expr) => {
110 $context_struct.rdi
111 };
112 (@impl 4, $context_struct:expr) => {
113 $context_struct.r8
114 };
115 (@impl 5, $context_struct:expr) => {
116 $context_struct.r9
117 };
118 (@impl 6, $context_struct:expr) => {
119 $context_struct.r10
120 };
121 (@impl $rest:tt, $context_struct:expr) => {
122 compile_error!("Not valid argument number")
123 };
124}
125
126#[macro_export]
127macro_rules! to_arg_err {
128 ($num:tt, $err:expr) => {
129 to_arg_err!(@impl $num, $err)
130 };
131 (@impl 0, $err:expr) => {
132 $crate::syscalls::SyscallError::InvalidArgument(::core::option::Option::Some($err), None, None, None, None, None, None)
133 };
134 (@impl 1, $err:expr) => {
135 $crate::syscalls::SyscallError::InvalidArgument(None, ::core::option::Option::Some($err), None, None, None, None, None)
136 };
137 (@impl 2, $err:expr) => {
138 $crate::syscalls::SyscallError::InvalidArgument(None, None, ::core::option::Option::Some($err), None, None, None, None)
139 };
140 (@impl 3, $err:expr) => {
141 $crate::syscalls::SyscallError::InvalidArgument(None, None, None, ::core::option::Option::Some($err), None, None, None)
142 };
143 (@impl 4, $err:expr) => {
144 $crate::syscalls::SyscallError::InvalidArgument(None, None, None, None, ::core::option::Option::Some($err), None, None)
145 };
146 (@impl 5, $err:expr) => {
147 $crate::syscalls::SyscallError::InvalidArgument(None, None, None, None, None, ::core::option::Option::Some($err), None)
148 };
149 (@impl 6, $err:expr) => {
150 $crate::syscalls::SyscallError::InvalidArgument(None, None, None, None, None, None, ::core::option::Option::Some($err))
151 };
152 (@impl $rest:tt, $err:expr) => {
153 compile_error!("Not valid argument number")
154 };
155}
156
157#[macro_export]
158macro_rules! verify_args {
159 () => {((), (), (), (), (), (), ())};
160 ($arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr, $arg6:expr, $arg7:expr) => {
161 match ($arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7) {
162 (
163 Ok(a),
164 Ok(b),
165 Ok(c),
166 Ok(d),
167 Ok(e),
168 Ok(f),
169 Ok(g),
170 ) => {(a, b, c, d, e, f, g)}
171 err => {
172 return $crate::syscalls::SyscallResult::Err(
173 $crate::syscalls::SyscallError::InvalidArgument(
174 err.0.err(), err.1.err(), err.2.err(), err.3.err(), err.4.err(), err.5.err(), err.6.err(),
175 ),
176 )
177 }
178 }
179 };
180 ($arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr, $arg6:expr, $arg7:expr, $extra:expr) => {
181 compile_error!("Too many arguments for syscall")
182 };
183 ($($args:expr),* $(,)?) => {
185 verify_args!($($args ,)* Ok(()))
186 };
187}
188
189pub trait FromSyscallArgU64 {
190 fn from_syscall_arg_u64(value: u64) -> Result<Self, SyscallArgError>
191 where
192 Self: Sized;
193}
194
195pub fn syscall_arg_to_u64<T: FromSyscallArgU64>(value: u64) -> Result<T, SyscallArgError> {
196 T::from_syscall_arg_u64(value)
197}
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
200#[repr(u8)]
201#[non_exhaustive]
202pub enum SyscallArgError {
203 GeneralInvalid = 1,
205 InvalidUserPointer = 2,
206 NotValidUtf8 = 3,
207 InvalidHeapIncrement = 4,
208 DuplicateFileMappings = 5,
209 InvalidNanoseconds = 6,
210}
211
212impl SyscallArgError {
213 fn try_from(value: u8) -> Result<Option<Self>, ()> {
214 match value {
215 0 => Ok(None),
216 1 => Ok(Some(SyscallArgError::GeneralInvalid)),
217 2 => Ok(Some(SyscallArgError::InvalidUserPointer)),
218 3 => Ok(Some(SyscallArgError::NotValidUtf8)),
219 4 => Ok(Some(SyscallArgError::InvalidHeapIncrement)),
220 5 => Ok(Some(SyscallArgError::DuplicateFileMappings)),
221 6 => Ok(Some(SyscallArgError::InvalidNanoseconds)),
222 _ => Err(()),
223 }
224 }
225}
226
227#[repr(align(8))]
228#[derive(Debug, Clone, Copy)]
229#[repr(u8)]
230#[non_exhaustive]
231pub enum SyscallError {
232 SyscallNotFound = 0,
233 InvalidError = 1,
234 CouldNotOpenFile = 2,
235 InvalidFileIndex = 3,
236 CouldNotWriteToFile = 4,
237 CouldNotReadFromFile = 5,
238 CouldNotLoadElf = 6,
239 CouldNotAllocateProcess = 7,
240 HeapRangesExceeded = 8,
241 EndOfFile = 9,
242 FileNotFound = 10,
243 PidNotFound = 11,
244 ProcessStillRunning = 12,
245 IsNotDirectory = 13,
246 IsDirectory = 14,
247 BufferTooSmall = 15,
248 GraphicsNotAvailable = 16,
249 GraphicsAlreadyTaken = 17,
250 GraphicsNotOwned = 18,
251 InvalidGraphicsBuffer = 19,
252 InvalidOffset = 20,
253 AlreadyExists = 21,
254 OperationNotSupported = 22,
255 InvalidArgument(
256 Option<SyscallArgError>,
257 Option<SyscallArgError>,
258 Option<SyscallArgError>,
259 Option<SyscallArgError>,
260 Option<SyscallArgError>,
261 Option<SyscallArgError>,
262 Option<SyscallArgError>,
263 ),
264}
265
266pub type SyscallResult = Result<u64, SyscallError>;
267
268impl From<SyscallError> for SyscallResult {
269 fn from(error: SyscallError) -> Self {
270 SyscallResult::Err(error)
271 }
272}
273
274fn create_syscall_error(
282 arg1: Option<SyscallArgError>,
283 arg2: Option<SyscallArgError>,
284 arg3: Option<SyscallArgError>,
285 arg4: Option<SyscallArgError>,
286 arg5: Option<SyscallArgError>,
287 arg6: Option<SyscallArgError>,
288 arg7: Option<SyscallArgError>,
289) -> u64 {
290 let mut error = 0u64;
291 error |= arg1.map(|e| e as u64).unwrap_or(0);
292 error |= arg2.map(|e| e as u64).unwrap_or(0) << 8;
293 error |= arg3.map(|e| e as u64).unwrap_or(0) << 16;
294 error |= arg4.map(|e| e as u64).unwrap_or(0) << 24;
295 error |= arg5.map(|e| e as u64).unwrap_or(0) << 32;
296 error |= arg6.map(|e| e as u64).unwrap_or(0) << 40;
297 error |= arg7.map(|e| e as u64).unwrap_or(0) << 48;
298 error |= 1 << 63;
299 error
300}
301
302#[inline(always)]
303pub fn syscall_handler_wrapper<F>(syscall_number: u64, f: F) -> u64
304where
305 F: FnOnce() -> SyscallResult,
306{
307 if syscall_number >= NUM_SYSCALLS as u64 {
308 return syscall_result_to_u64(SyscallResult::Err(SyscallError::SyscallNotFound));
309 }
310 let result = f();
311 syscall_result_to_u64(result)
312}
313
314pub fn syscall_result_to_u64(result: SyscallResult) -> u64 {
315 match result {
316 SyscallResult::Ok(value) => {
317 assert!(
318 value & (1 << 63) == 0,
319 "syscall result should not have msb set"
320 );
321 value
322 }
323 SyscallResult::Err(error) => {
324 let err_upper = match error {
325 SyscallError::SyscallNotFound => -1i64 as u64,
326 SyscallError::InvalidArgument(arg1, arg2, arg3, arg4, arg5, arg6, arg7) => {
327 create_syscall_error(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
328 }
329 SyscallError::CouldNotOpenFile => 2 << 56,
330 SyscallError::InvalidFileIndex => 3 << 56,
331 SyscallError::CouldNotWriteToFile => 4 << 56,
332 SyscallError::CouldNotReadFromFile => 5 << 56,
333 SyscallError::CouldNotLoadElf => 6 << 56,
334 SyscallError::CouldNotAllocateProcess => 7 << 56,
335 SyscallError::HeapRangesExceeded => 8 << 56,
336 SyscallError::EndOfFile => 9 << 56,
337 SyscallError::FileNotFound => 10 << 56,
338 SyscallError::PidNotFound => 11 << 56,
339 SyscallError::ProcessStillRunning => 12 << 56,
340 SyscallError::IsNotDirectory => 13 << 56,
341 SyscallError::IsDirectory => 14 << 56,
342 SyscallError::BufferTooSmall => 15 << 56,
343 SyscallError::GraphicsNotAvailable => 16 << 56,
344 SyscallError::GraphicsAlreadyTaken => 17 << 56,
345 SyscallError::GraphicsNotOwned => 18 << 56,
346 SyscallError::InvalidGraphicsBuffer => 19 << 56,
347 SyscallError::InvalidOffset => 20 << 56,
348 SyscallError::AlreadyExists => 21 << 56,
349 SyscallError::OperationNotSupported => 22 << 56,
350 SyscallError::InvalidError => panic!("Should never be used"),
351 };
352
353 err_upper | (1 << 63)
354 }
355 }
356}
357
358pub fn syscall_result_from_u64(value: u64) -> SyscallResult {
359 if value & (1 << 63) == 0 {
360 SyscallResult::Ok(value)
361 } else {
362 let value = value & !(1 << 63);
364 let err_byte = (value >> 56) as u8;
366
367 let invalid_error_code = |_| SyscallError::InvalidError;
368
369 let err = match err_byte {
370 0 => {
371 let arg1 =
372 SyscallArgError::try_from((value & 0xFF) as u8).map_err(invalid_error_code)?;
373 let arg2 = SyscallArgError::try_from(((value >> 8) & 0xFF) as u8)
374 .map_err(invalid_error_code)?;
375 let arg3 = SyscallArgError::try_from(((value >> 16) & 0xFF) as u8)
376 .map_err(invalid_error_code)?;
377 let arg4 = SyscallArgError::try_from(((value >> 24) & 0xFF) as u8)
378 .map_err(invalid_error_code)?;
379 let arg5 = SyscallArgError::try_from(((value >> 32) & 0xFF) as u8)
380 .map_err(invalid_error_code)?;
381 let arg6 = SyscallArgError::try_from(((value >> 40) & 0xFF) as u8)
382 .map_err(invalid_error_code)?;
383 let arg7 = SyscallArgError::try_from(((value >> 48) & 0xFF) as u8)
384 .map_err(invalid_error_code)?;
385
386 SyscallError::InvalidArgument(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
387 }
388 1 => SyscallError::InvalidError,
389 2 => SyscallError::CouldNotOpenFile,
390 3 => SyscallError::InvalidFileIndex,
391 4 => SyscallError::CouldNotWriteToFile,
392 5 => SyscallError::CouldNotReadFromFile,
393 6 => SyscallError::CouldNotLoadElf,
394 7 => SyscallError::CouldNotAllocateProcess,
395 8 => SyscallError::HeapRangesExceeded,
396 9 => SyscallError::EndOfFile,
397 10 => SyscallError::FileNotFound,
398 11 => SyscallError::PidNotFound,
399 12 => SyscallError::ProcessStillRunning,
400 13 => SyscallError::IsNotDirectory,
401 14 => SyscallError::IsDirectory,
402 15 => SyscallError::BufferTooSmall,
403 16 => SyscallError::GraphicsNotAvailable,
404 17 => SyscallError::GraphicsAlreadyTaken,
405 18 => SyscallError::GraphicsNotOwned,
406 19 => SyscallError::InvalidGraphicsBuffer,
407 20 => SyscallError::InvalidOffset,
408 21 => SyscallError::AlreadyExists,
409 22 => SyscallError::OperationNotSupported,
410 _ => SyscallError::InvalidError,
411 };
412 SyscallResult::Err(err)
413 }
414}