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