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