1 //! `hermit-abi` is small interface to call functions from the unikernel
2 //! [RustyHermit](https://github.com/hermitcore/libhermit-rs).
3 
4 #![no_std]
5 #![allow(clippy::missing_safety_doc)]
6 #![allow(clippy::result_unit_err)]
7 
8 extern crate libc;
9 
10 pub mod tcplistener;
11 pub mod tcpstream;
12 
13 use libc::c_void;
14 
15 // sysmbols, which are part of the library operating system
16 
17 extern "Rust" {
sys_secure_rand64() -> Option<u64>18 	fn sys_secure_rand64() -> Option<u64>;
sys_secure_rand32() -> Option<u32>19 	fn sys_secure_rand32() -> Option<u32>;
20 }
21 
22 extern "C" {
sys_rand() -> u3223 	fn sys_rand() -> u32;
sys_srand(seed: u32)24 	fn sys_srand(seed: u32);
sys_get_processor_count() -> usize25 	fn sys_get_processor_count() -> usize;
sys_malloc(size: usize, align: usize) -> *mut u826 	fn sys_malloc(size: usize, align: usize) -> *mut u8;
sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u827 	fn sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8;
sys_free(ptr: *mut u8, size: usize, align: usize)28 	fn sys_free(ptr: *mut u8, size: usize, align: usize);
sys_init_queue(ptr: usize) -> i3229 	fn sys_init_queue(ptr: usize) -> i32;
sys_notify(id: usize, count: i32) -> i3230 	fn sys_notify(id: usize, count: i32) -> i32;
sys_add_queue(id: usize, timeout_ns: i64) -> i3231 	fn sys_add_queue(id: usize, timeout_ns: i64) -> i32;
sys_wait(id: usize) -> i3232 	fn sys_wait(id: usize) -> i32;
sys_destroy_queue(id: usize) -> i3233 	fn sys_destroy_queue(id: usize) -> i32;
sys_read(fd: i32, buf: *mut u8, len: usize) -> isize34 	fn sys_read(fd: i32, buf: *mut u8, len: usize) -> isize;
sys_write(fd: i32, buf: *const u8, len: usize) -> isize35 	fn sys_write(fd: i32, buf: *const u8, len: usize) -> isize;
sys_close(fd: i32) -> i3236 	fn sys_close(fd: i32) -> i32;
sys_sem_init(sem: *mut *const c_void, value: u32) -> i3237 	fn sys_sem_init(sem: *mut *const c_void, value: u32) -> i32;
sys_sem_destroy(sem: *const c_void) -> i3238 	fn sys_sem_destroy(sem: *const c_void) -> i32;
sys_sem_post(sem: *const c_void) -> i3239 	fn sys_sem_post(sem: *const c_void) -> i32;
sys_sem_trywait(sem: *const c_void) -> i3240 	fn sys_sem_trywait(sem: *const c_void) -> i32;
sys_sem_timedwait(sem: *const c_void, ms: u32) -> i3241 	fn sys_sem_timedwait(sem: *const c_void, ms: u32) -> i32;
sys_recmutex_init(recmutex: *mut *const c_void) -> i3242 	fn sys_recmutex_init(recmutex: *mut *const c_void) -> i32;
sys_recmutex_destroy(recmutex: *const c_void) -> i3243 	fn sys_recmutex_destroy(recmutex: *const c_void) -> i32;
sys_recmutex_lock(recmutex: *const c_void) -> i3244 	fn sys_recmutex_lock(recmutex: *const c_void) -> i32;
sys_recmutex_unlock(recmutex: *const c_void) -> i3245 	fn sys_recmutex_unlock(recmutex: *const c_void) -> i32;
sys_getpid() -> u3246 	fn sys_getpid() -> u32;
sys_exit(arg: i32) -> !47 	fn sys_exit(arg: i32) -> !;
sys_abort() -> !48 	fn sys_abort() -> !;
sys_usleep(usecs: u64)49 	fn sys_usleep(usecs: u64);
sys_spawn( id: *mut Tid, func: extern "C" fn(usize), arg: usize, prio: u8, core_id: isize, ) -> i3250 	fn sys_spawn(
51 		id: *mut Tid,
52 		func: extern "C" fn(usize),
53 		arg: usize,
54 		prio: u8,
55 		core_id: isize,
56 	) -> i32;
sys_spawn2( func: extern "C" fn(usize), arg: usize, prio: u8, stack_size: usize, core_id: isize, ) -> Tid57 	fn sys_spawn2(
58 		func: extern "C" fn(usize),
59 		arg: usize,
60 		prio: u8,
61 		stack_size: usize,
62 		core_id: isize,
63 	) -> Tid;
sys_join(id: Tid) -> i3264 	fn sys_join(id: Tid) -> i32;
sys_yield()65 	fn sys_yield();
sys_clock_gettime(clock_id: u64, tp: *mut timespec) -> i3266 	fn sys_clock_gettime(clock_id: u64, tp: *mut timespec) -> i32;
sys_open(name: *const i8, flags: i32, mode: i32) -> i3267 	fn sys_open(name: *const i8, flags: i32, mode: i32) -> i32;
sys_unlink(name: *const i8) -> i3268 	fn sys_unlink(name: *const i8) -> i32;
sys_network_init() -> i3269 	fn sys_network_init() -> i32;
sys_block_current_task()70 	fn sys_block_current_task();
sys_wakeup_task(tid: Tid)71 	fn sys_wakeup_task(tid: Tid);
sys_get_priority() -> u872 	fn sys_get_priority() -> u8;
73 }
74 
75 /// A thread handle type
76 pub type Tid = u32;
77 
78 /// Maximum number of priorities
79 pub const NO_PRIORITIES: usize = 31;
80 
81 /// Priority of a thread
82 #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
83 pub struct Priority(u8);
84 
85 impl Priority {
into(self) -> u886 	pub const fn into(self) -> u8 {
87 		self.0
88 	}
89 
from(x: u8) -> Self90 	pub const fn from(x: u8) -> Self {
91 		Priority(x)
92 	}
93 }
94 
95 pub const HIGH_PRIO: Priority = Priority::from(3);
96 pub const NORMAL_PRIO: Priority = Priority::from(2);
97 pub const LOW_PRIO: Priority = Priority::from(1);
98 
99 /// A handle, identifying a socket
100 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
101 pub struct Handle(usize);
102 
103 pub const NSEC_PER_SEC: u64 = 1_000_000_000;
104 pub const CLOCK_REALTIME: u64 = 1;
105 pub const CLOCK_MONOTONIC: u64 = 4;
106 pub const STDIN_FILENO: libc::c_int = 0;
107 pub const STDOUT_FILENO: libc::c_int = 1;
108 pub const STDERR_FILENO: libc::c_int = 2;
109 pub const O_RDONLY: i32 = 0o0;
110 pub const O_WRONLY: i32 = 0o1;
111 pub const O_RDWR: i32 = 0o2;
112 pub const O_CREAT: i32 = 0o100;
113 pub const O_EXCL: i32 = 0o200;
114 pub const O_TRUNC: i32 = 0o1000;
115 pub const O_APPEND: i32 = 0o2000;
116 
117 /// returns true if file descriptor `fd` is a tty
isatty(_fd: libc::c_int) -> bool118 pub fn isatty(_fd: libc::c_int) -> bool {
119 	false
120 }
121 
122 /// intialize the network stack
network_init() -> i32123 pub fn network_init() -> i32 {
124 	unsafe { sys_network_init() }
125 }
126 
127 /// `timespec` is used by `clock_gettime` to retrieve the
128 /// current time
129 #[derive(Copy, Clone, Debug)]
130 #[repr(C)]
131 pub struct timespec {
132 	/// seconds
133 	pub tv_sec: i64,
134 	/// nanoseconds
135 	pub tv_nsec: i64,
136 }
137 
138 /// Internet protocol version.
139 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
140 pub enum Version {
141 	Unspecified,
142 	Ipv4,
143 	Ipv6,
144 }
145 
146 /// A four-octet IPv4 address.
147 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
148 pub struct Ipv4Address(pub [u8; 4]);
149 
150 /// A sixteen-octet IPv6 address.
151 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
152 pub struct Ipv6Address(pub [u8; 16]);
153 
154 /// An internetworking address.
155 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
156 pub enum IpAddress {
157 	/// An unspecified address.
158 	/// May be used as a placeholder for storage where the address is not assigned yet.
159 	Unspecified,
160 	/// An IPv4 address.
161 	Ipv4(Ipv4Address),
162 	/// An IPv6 address.
163 	Ipv6(Ipv6Address),
164 }
165 
166 /// determines the number of activated processors
167 #[inline(always)]
get_processor_count() -> usize168 pub unsafe fn get_processor_count() -> usize {
169 	sys_get_processor_count()
170 }
171 
172 #[doc(hidden)]
173 #[inline(always)]
malloc(size: usize, align: usize) -> *mut u8174 pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 {
175 	sys_malloc(size, align)
176 }
177 
178 #[doc(hidden)]
179 #[inline(always)]
realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8180 pub unsafe fn realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8 {
181 	sys_realloc(ptr, size, align, new_size)
182 }
183 
184 #[doc(hidden)]
185 #[inline(always)]
free(ptr: *mut u8, size: usize, align: usize)186 pub unsafe fn free(ptr: *mut u8, size: usize, align: usize) {
187 	sys_free(ptr, size, align)
188 }
189 
190 #[inline(always)]
notify(id: usize, count: i32) -> i32191 pub unsafe fn notify(id: usize, count: i32) -> i32 {
192 	sys_notify(id, count)
193 }
194 
195 #[doc(hidden)]
196 #[inline(always)]
add_queue(id: usize, timeout_ns: i64) -> i32197 pub unsafe fn add_queue(id: usize, timeout_ns: i64) -> i32 {
198 	sys_add_queue(id, timeout_ns)
199 }
200 
201 #[doc(hidden)]
202 #[inline(always)]
wait(id: usize) -> i32203 pub unsafe fn wait(id: usize) -> i32 {
204 	sys_wait(id)
205 }
206 
207 #[doc(hidden)]
208 #[inline(always)]
init_queue(id: usize) -> i32209 pub unsafe fn init_queue(id: usize) -> i32 {
210 	sys_init_queue(id)
211 }
212 
213 #[doc(hidden)]
214 #[inline(always)]
destroy_queue(id: usize) -> i32215 pub unsafe fn destroy_queue(id: usize) -> i32 {
216 	sys_destroy_queue(id)
217 }
218 
219 /// read from a file descriptor
220 ///
221 /// read() attempts to read `len` bytes of data from the object
222 /// referenced by the descriptor `fd` into the buffer pointed
223 /// to by `buf`.
224 #[inline(always)]
read(fd: i32, buf: *mut u8, len: usize) -> isize225 pub unsafe fn read(fd: i32, buf: *mut u8, len: usize) -> isize {
226 	sys_read(fd, buf, len)
227 }
228 
229 /// write to a file descriptor
230 ///
231 /// write() attempts to write `len` of data to the object
232 /// referenced by the descriptor `fd` from the
233 /// buffer pointed to by `buf`.
234 #[inline(always)]
write(fd: i32, buf: *const u8, len: usize) -> isize235 pub unsafe fn write(fd: i32, buf: *const u8, len: usize) -> isize {
236 	sys_write(fd, buf, len)
237 }
238 
239 /// close a file descriptor
240 ///
241 /// The close() call deletes a file descriptor `fd` from the object
242 /// reference table.
243 #[inline(always)]
close(fd: i32) -> i32244 pub unsafe fn close(fd: i32) -> i32 {
245 	sys_close(fd)
246 }
247 
248 /// sem_init() initializes the unnamed semaphore at the address
249 /// pointed to by `sem`.  The `value` argument specifies the
250 /// initial value for the semaphore.
251 #[inline(always)]
sem_init(sem: *mut *const c_void, value: u32) -> i32252 pub unsafe fn sem_init(sem: *mut *const c_void, value: u32) -> i32 {
253 	sys_sem_init(sem, value)
254 }
255 
256 /// sem_destroy() frees the unnamed semaphore at the address
257 /// pointed to by `sem`.
258 #[inline(always)]
sem_destroy(sem: *const c_void) -> i32259 pub unsafe fn sem_destroy(sem: *const c_void) -> i32 {
260 	sys_sem_destroy(sem)
261 }
262 
263 /// sem_post() increments the semaphore pointed to by `sem`.
264 /// If the semaphore's value consequently becomes greater
265 /// than zero, then another thread blocked in a sem_wait call
266 /// will be woken up and proceed to lock the semaphore.
267 #[inline(always)]
sem_post(sem: *const c_void) -> i32268 pub unsafe fn sem_post(sem: *const c_void) -> i32 {
269 	sys_sem_post(sem)
270 }
271 
272 /// try to decrement a semaphore
273 ///
274 /// sem_trywait() is the same as sem_timedwait(), except that
275 /// if the  decrement cannot be immediately performed, then  call
276 /// returns a negative value instead of blocking.
277 #[inline(always)]
sem_trywait(sem: *const c_void) -> i32278 pub unsafe fn sem_trywait(sem: *const c_void) -> i32 {
279 	sys_sem_trywait(sem)
280 }
281 
282 /// decrement a semaphore
283 ///
284 /// sem_timedwait() decrements the semaphore pointed to by `sem`.
285 /// If the semaphore's value is greater than zero, then the
286 /// the function returns immediately. If the semaphore currently
287 /// has the value zero, then the call blocks until either
288 /// it becomes possible to perform the decrement of the time limit
289 /// to wait for the semaphore is expired. A time limit `ms` of
290 /// means infinity waiting time.
291 #[inline(always)]
sem_timedwait(sem: *const c_void, ms: u32) -> i32292 pub unsafe fn sem_timedwait(sem: *const c_void, ms: u32) -> i32 {
293 	sys_sem_timedwait(sem, ms)
294 }
295 
296 #[doc(hidden)]
297 #[inline(always)]
recmutex_init(recmutex: *mut *const c_void) -> i32298 pub unsafe fn recmutex_init(recmutex: *mut *const c_void) -> i32 {
299 	sys_recmutex_init(recmutex)
300 }
301 
302 #[doc(hidden)]
303 #[inline(always)]
recmutex_destroy(recmutex: *const c_void) -> i32304 pub unsafe fn recmutex_destroy(recmutex: *const c_void) -> i32 {
305 	sys_recmutex_destroy(recmutex)
306 }
307 
308 #[doc(hidden)]
309 #[inline(always)]
recmutex_lock(recmutex: *const c_void) -> i32310 pub unsafe fn recmutex_lock(recmutex: *const c_void) -> i32 {
311 	sys_recmutex_lock(recmutex)
312 }
313 
314 #[doc(hidden)]
315 #[inline(always)]
recmutex_unlock(recmutex: *const c_void) -> i32316 pub unsafe fn recmutex_unlock(recmutex: *const c_void) -> i32 {
317 	sys_recmutex_unlock(recmutex)
318 }
319 
320 /// Determines the id of the current thread
321 #[inline(always)]
getpid() -> u32322 pub unsafe fn getpid() -> u32 {
323 	sys_getpid()
324 }
325 
326 /// cause normal termination and return `arg`
327 /// to the host system
328 #[inline(always)]
exit(arg: i32) -> !329 pub unsafe fn exit(arg: i32) -> ! {
330 	sys_exit(arg)
331 }
332 
333 /// cause abnormal termination
334 #[inline(always)]
abort() -> !335 pub unsafe fn abort() -> ! {
336 	sys_abort()
337 }
338 
339 /// suspend execution for microsecond intervals
340 ///
341 /// The usleep() function suspends execution of the calling
342 /// thread for (at least) `usecs` microseconds.
343 #[inline(always)]
usleep(usecs: u64)344 pub unsafe fn usleep(usecs: u64) {
345 	sys_usleep(usecs)
346 }
347 
348 /// spawn a new thread
349 ///
350 /// spawn() starts a new thread. The new thread starts execution
351 /// by invoking `func(usize)`; `arg` is passed as the argument
352 /// to `func`. `prio` defines the priority of the new thread,
353 /// which can be between `LOW_PRIO` and `HIGH_PRIO`.
354 /// `core_id` defines the core, where the thread is located.
355 /// A negative value give the operating system the possibility
356 /// to select the core by its own.
357 #[inline(always)]
spawn( id: *mut Tid, func: extern "C" fn(usize), arg: usize, prio: u8, core_id: isize, ) -> i32358 pub unsafe fn spawn(
359 	id: *mut Tid,
360 	func: extern "C" fn(usize),
361 	arg: usize,
362 	prio: u8,
363 	core_id: isize,
364 ) -> i32 {
365 	sys_spawn(id, func, arg, prio, core_id)
366 }
367 
368 /// spawn a new thread with user-specified stack size
369 ///
370 /// spawn2() starts a new thread. The new thread starts execution
371 /// by invoking `func(usize)`; `arg` is passed as the argument
372 /// to `func`. `prio` defines the priority of the new thread,
373 /// which can be between `LOW_PRIO` and `HIGH_PRIO`.
374 /// `core_id` defines the core, where the thread is located.
375 /// A negative value give the operating system the possibility
376 /// to select the core by its own.
377 /// In contrast to spawn(), spawn2() is able to define the
378 /// stack size.
379 #[inline(always)]
spawn2( func: extern "C" fn(usize), arg: usize, prio: u8, stack_size: usize, core_id: isize, ) -> Tid380 pub unsafe fn spawn2(
381 	func: extern "C" fn(usize),
382 	arg: usize,
383 	prio: u8,
384 	stack_size: usize,
385 	core_id: isize,
386 ) -> Tid {
387 	sys_spawn2(func, arg, prio, stack_size, core_id)
388 }
389 
390 /// join with a terminated thread
391 ///
392 /// The join() function waits for the thread specified by `id`
393 /// to terminate.
394 #[inline(always)]
join(id: Tid) -> i32395 pub unsafe fn join(id: Tid) -> i32 {
396 	sys_join(id)
397 }
398 
399 /// yield the processor
400 ///
401 /// causes the calling thread to relinquish the CPU. The thread
402 /// is moved to the end of the queue for its static priority.
403 #[inline(always)]
yield_now()404 pub unsafe fn yield_now() {
405 	sys_yield()
406 }
407 
408 /// get current time
409 ///
410 /// The clock_gettime() functions allow the calling thread
411 /// to retrieve the value used by a clock which is specified
412 /// by `clock_id`.
413 ///
414 /// `CLOCK_REALTIME`: the system's real time clock,
415 /// expressed as the amount of time since the Epoch.
416 ///
417 /// `CLOCK_MONOTONIC`: clock that increments monotonically,
418 /// tracking the time since an arbitrary point
419 #[inline(always)]
clock_gettime(clock_id: u64, tp: *mut timespec) -> i32420 pub unsafe fn clock_gettime(clock_id: u64, tp: *mut timespec) -> i32 {
421 	sys_clock_gettime(clock_id, tp)
422 }
423 
424 /// open and possibly create a file
425 ///
426 /// The open() system call opens the file specified by `name`.
427 /// If the specified file does not exist, it may optionally
428 /// be created by open().
429 #[inline(always)]
open(name: *const i8, flags: i32, mode: i32) -> i32430 pub unsafe fn open(name: *const i8, flags: i32, mode: i32) -> i32 {
431 	sys_open(name, flags, mode)
432 }
433 
434 /// delete the file it refers to `name`
435 #[inline(always)]
unlink(name: *const i8) -> i32436 pub unsafe fn unlink(name: *const i8) -> i32 {
437 	sys_unlink(name)
438 }
439 
440 /// The largest number `rand` will return
441 pub const RAND_MAX: u64 = 2_147_483_647;
442 
443 /// The function computes a sequence of pseudo-random integers
444 /// in the range of 0 to RAND_MAX
445 #[inline(always)]
rand() -> u32446 pub unsafe fn rand() -> u32 {
447 	sys_rand()
448 }
449 
450 /// The function sets its argument as the seed for a new sequence
451 /// of pseudo-random numbers to be returned by `rand`
452 #[inline(always)]
srand(seed: u32)453 pub unsafe fn srand(seed: u32) {
454 	sys_srand(seed);
455 }
456 
457 /// Create a cryptographicly secure 32bit random number with the support of
458 /// the underlying hardware. If the required hardware isn't available,
459 /// the function returns `None`.
460 #[inline(always)]
secure_rand32() -> Option<u32>461 pub unsafe fn secure_rand32() -> Option<u32> {
462 	sys_secure_rand32()
463 }
464 
465 /// Create a cryptographicly secure 64bit random number with the support of
466 /// the underlying hardware. If the required hardware isn't available,
467 /// the function returns `None`.
468 #[inline(always)]
secure_rand64() -> Option<u64>469 pub unsafe fn secure_rand64() -> Option<u64> {
470 	sys_secure_rand64()
471 }
472 
473 /// Add current task to the queue of blocked tasl. After calling `block_current_task`,
474 /// call `yield_now` to switch to another task.
475 #[inline(always)]
block_current_task()476 pub unsafe fn block_current_task() {
477 	sys_block_current_task();
478 }
479 
480 /// Wakeup task with the thread id `tid`
481 #[inline(always)]
wakeup_task(tid: Tid)482 pub unsafe fn wakeup_task(tid: Tid) {
483 	sys_wakeup_task(tid);
484 }
485 
486 /// Determine the priority of the current thread
487 #[inline(always)]
get_priority() -> Priority488 pub unsafe fn get_priority() -> Priority {
489 	Priority::from(sys_get_priority())
490 }
491