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 extern "C" {
15 	fn sys_get_processor_count() -> usize;
16 	fn sys_malloc(size: usize, align: usize) -> *mut u8;
17 	fn sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8;
18 	fn sys_free(ptr: *mut u8, size: usize, align: usize);
19 	fn sys_init_queue(ptr: usize) -> i32;
20 	fn sys_notify(id: usize, count: i32) -> i32;
21 	fn sys_add_queue(id: usize, timeout_ns: i64) -> i32;
22 	fn sys_wait(id: usize) -> i32;
23 	fn sys_destroy_queue(id: usize) -> i32;
24 	fn sys_read(fd: i32, buf: *mut u8, len: usize) -> isize;
25 	fn sys_write(fd: i32, buf: *const u8, len: usize) -> isize;
26 	fn sys_close(fd: i32) -> i32;
27 	fn sys_sem_init(sem: *mut *const c_void, value: u32) -> i32;
28 	fn sys_sem_destroy(sem: *const c_void) -> i32;
29 	fn sys_sem_post(sem: *const c_void) -> i32;
30 	fn sys_sem_trywait(sem: *const c_void) -> i32;
31 	fn sys_sem_timedwait(sem: *const c_void, ms: u32) -> i32;
32 	fn sys_recmutex_init(recmutex: *mut *const c_void) -> i32;
33 	fn sys_recmutex_destroy(recmutex: *const c_void) -> i32;
34 	fn sys_recmutex_lock(recmutex: *const c_void) -> i32;
35 	fn sys_recmutex_unlock(recmutex: *const c_void) -> i32;
36 	fn sys_getpid() -> u32;
37 	fn sys_exit(arg: i32) -> !;
38 	fn sys_abort() -> !;
39 	fn sys_usleep(usecs: u64);
40 	fn sys_spawn(
41 		id: *mut Tid,
42 		func: extern "C" fn(usize),
43 		arg: usize,
44 		prio: u8,
45 		core_id: isize,
46 	) -> i32;
47 	fn sys_spawn2(
48 		func: extern "C" fn(usize),
49 		arg: usize,
50 		prio: u8,
51 		stack_size: usize,
52 		core_id: isize,
53 	) -> Tid;
54 	fn sys_join(id: Tid) -> i32;
55 	fn sys_yield();
56 	fn sys_clock_gettime(clock_id: u64, tp: *mut timespec) -> i32;
57 	fn sys_open(name: *const i8, flags: i32, mode: i32) -> i32;
58 	fn sys_unlink(name: *const i8) -> i32;
59 	fn sys_network_init() -> i32;
60 }
61 
62 /// A thread handle type
63 pub type Tid = u32;
64 
65 /// Priority of a thread
66 #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
67 pub struct Priority(u8);
68 
69 impl Priority {
70 	pub const fn into(self) -> u8 {
71 		self.0
72 	}
73 
74 	pub const fn from(x: u8) -> Self {
75 		Priority(x)
76 	}
77 }
78 
79 pub const HIGH_PRIO: Priority = Priority::from(3);
80 pub const NORMAL_PRIO: Priority = Priority::from(2);
81 pub const LOW_PRIO: Priority = Priority::from(1);
82 
83 /// A handle, identifying a socket
84 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
85 pub struct Handle(usize);
86 
87 pub const NSEC_PER_SEC: u64 = 1_000_000_000;
88 pub const CLOCK_REALTIME: u64 = 1;
89 pub const CLOCK_MONOTONIC: u64 = 4;
90 pub const STDIN_FILENO: libc::c_int = 0;
91 pub const STDOUT_FILENO: libc::c_int = 1;
92 pub const STDERR_FILENO: libc::c_int = 2;
93 pub const O_RDONLY: i32 = 0o0;
94 pub const O_WRONLY: i32 = 0o1;
95 pub const O_RDWR: i32 = 0o2;
96 pub const O_CREAT: i32 = 0o100;
97 pub const O_EXCL: i32 = 0o200;
98 pub const O_TRUNC: i32 = 0o1000;
99 pub const O_APPEND: i32 = 0o2000;
100 
101 /// returns true if file descriptor `fd` is a tty
102 pub fn isatty(_fd: libc::c_int) -> bool {
103 	false
104 }
105 
106 /// intialize the network stack
107 pub fn network_init() -> i32 {
108 	unsafe { sys_network_init() }
109 }
110 
111 /// `timespec` is used by `clock_gettime` to retrieve the
112 /// current time
113 #[derive(Copy, Clone, Debug)]
114 #[repr(C)]
115 pub struct timespec {
116 	/// seconds
117 	pub tv_sec: i64,
118 	/// nanoseconds
119 	pub tv_nsec: i64,
120 }
121 
122 /// Internet protocol version.
123 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
124 pub enum Version {
125 	Unspecified,
126 	Ipv4,
127 	Ipv6,
128 }
129 
130 /// A four-octet IPv4 address.
131 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
132 pub struct Ipv4Address(pub [u8; 4]);
133 
134 /// A sixteen-octet IPv6 address.
135 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
136 pub struct Ipv6Address(pub [u8; 16]);
137 
138 /// An internetworking address.
139 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
140 pub enum IpAddress {
141 	/// An unspecified address.
142 	/// May be used as a placeholder for storage where the address is not assigned yet.
143 	Unspecified,
144 	/// An IPv4 address.
145 	Ipv4(Ipv4Address),
146 	/// An IPv6 address.
147 	Ipv6(Ipv6Address),
148 }
149 
150 /// determines the number of activated processors
151 #[inline(always)]
152 pub unsafe fn get_processor_count() -> usize {
153 	sys_get_processor_count()
154 }
155 
156 #[doc(hidden)]
157 #[inline(always)]
158 pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 {
159 	sys_malloc(size, align)
160 }
161 
162 #[doc(hidden)]
163 #[inline(always)]
164 pub unsafe fn realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8 {
165 	sys_realloc(ptr, size, align, new_size)
166 }
167 
168 #[doc(hidden)]
169 #[inline(always)]
170 pub unsafe fn free(ptr: *mut u8, size: usize, align: usize) {
171 	sys_free(ptr, size, align)
172 }
173 
174 #[inline(always)]
175 pub unsafe fn notify(id: usize, count: i32) -> i32 {
176 	sys_notify(id, count)
177 }
178 
179 #[doc(hidden)]
180 #[inline(always)]
181 pub unsafe fn add_queue(id: usize, timeout_ns: i64) -> i32 {
182 	sys_add_queue(id, timeout_ns)
183 }
184 
185 #[doc(hidden)]
186 #[inline(always)]
187 pub unsafe fn wait(id: usize) -> i32 {
188 	sys_wait(id)
189 }
190 
191 #[doc(hidden)]
192 #[inline(always)]
193 pub unsafe fn init_queue(id: usize) -> i32 {
194 	sys_init_queue(id)
195 }
196 
197 #[doc(hidden)]
198 #[inline(always)]
199 pub unsafe fn destroy_queue(id: usize) -> i32 {
200 	sys_destroy_queue(id)
201 }
202 
203 /// read from a file descriptor
204 ///
205 /// read() attempts to read `len` bytes of data from the object
206 /// referenced by the descriptor `fd` into the buffer pointed
207 /// to by `buf`.
208 #[inline(always)]
209 pub unsafe fn read(fd: i32, buf: *mut u8, len: usize) -> isize {
210 	sys_read(fd, buf, len)
211 }
212 
213 /// write to a file descriptor
214 ///
215 /// write() attempts to write `len` of data to the object
216 /// referenced by the descriptor `fd` from the
217 /// buffer pointed to by `buf`.
218 #[inline(always)]
219 pub unsafe fn write(fd: i32, buf: *const u8, len: usize) -> isize {
220 	sys_write(fd, buf, len)
221 }
222 
223 /// close a file descriptor
224 ///
225 /// The close() call deletes a file descriptor `fd` from the object
226 /// reference table.
227 #[inline(always)]
228 pub unsafe fn close(fd: i32) -> i32 {
229 	sys_close(fd)
230 }
231 
232 /// sem_init() initializes the unnamed semaphore at the address
233 /// pointed to by `sem`.  The `value` argument specifies the
234 /// initial value for the semaphore.
235 #[inline(always)]
236 pub unsafe fn sem_init(sem: *mut *const c_void, value: u32) -> i32 {
237 	sys_sem_init(sem, value)
238 }
239 
240 /// sem_destroy() frees the unnamed semaphore at the address
241 /// pointed to by `sem`.
242 #[inline(always)]
243 pub unsafe fn sem_destroy(sem: *const c_void) -> i32 {
244 	sys_sem_destroy(sem)
245 }
246 
247 /// sem_post() increments the semaphore pointed to by `sem`.
248 /// If the semaphore's value consequently becomes greater
249 /// than zero, then another thread blocked in a sem_wait call
250 /// will be woken up and proceed to lock the semaphore.
251 #[inline(always)]
252 pub unsafe fn sem_post(sem: *const c_void) -> i32 {
253 	sys_sem_post(sem)
254 }
255 
256 /// try to decrement a semaphore
257 ///
258 /// sem_trywait() is the same as sem_timedwait(), except that
259 /// if the  decrement cannot be immediately performed, then  call
260 /// returns a negative value instead of blocking.
261 #[inline(always)]
262 pub unsafe fn sem_trywait(sem: *const c_void) -> i32 {
263 	sys_sem_trywait(sem)
264 }
265 
266 /// decrement a semaphore
267 ///
268 /// sem_timedwait() decrements the semaphore pointed to by `sem`.
269 /// If the semaphore's value is greater than zero, then the
270 /// the function returns immediately. If the semaphore currently
271 /// has the value zero, then the call blocks until either
272 /// it becomes possible to perform the decrement of the time limit
273 /// to wait for the semaphore is expired. A time limit `ms` of
274 /// means infinity waiting time.
275 #[inline(always)]
276 pub unsafe fn sem_timedwait(sem: *const c_void, ms: u32) -> i32 {
277 	sys_sem_timedwait(sem, ms)
278 }
279 
280 #[doc(hidden)]
281 #[inline(always)]
282 pub unsafe fn recmutex_init(recmutex: *mut *const c_void) -> i32 {
283 	sys_recmutex_init(recmutex)
284 }
285 
286 #[doc(hidden)]
287 #[inline(always)]
288 pub unsafe fn recmutex_destroy(recmutex: *const c_void) -> i32 {
289 	sys_recmutex_destroy(recmutex)
290 }
291 
292 #[doc(hidden)]
293 #[inline(always)]
294 pub unsafe fn recmutex_lock(recmutex: *const c_void) -> i32 {
295 	sys_recmutex_lock(recmutex)
296 }
297 
298 #[doc(hidden)]
299 #[inline(always)]
300 pub unsafe fn recmutex_unlock(recmutex: *const c_void) -> i32 {
301 	sys_recmutex_unlock(recmutex)
302 }
303 
304 /// Determines the id of the current thread
305 #[inline(always)]
306 pub unsafe fn getpid() -> u32 {
307 	sys_getpid()
308 }
309 
310 /// cause normal termination and return `arg`
311 /// to the host system
312 #[inline(always)]
313 pub unsafe fn exit(arg: i32) -> ! {
314 	sys_exit(arg)
315 }
316 
317 /// cause abnormal termination
318 #[inline(always)]
319 pub unsafe fn abort() -> ! {
320 	sys_abort()
321 }
322 
323 /// suspend execution for microsecond intervals
324 ///
325 /// The usleep() function suspends execution of the calling
326 /// thread for (at least) `usecs` microseconds.
327 #[inline(always)]
328 pub unsafe fn usleep(usecs: u64) {
329 	sys_usleep(usecs)
330 }
331 
332 /// spawn a new thread
333 ///
334 /// spawn() starts a new thread. The new thread starts execution
335 /// by invoking `func(usize)`; `arg` is passed as the argument
336 /// to `func`. `prio` defines the priority of the new thread,
337 /// which can be between `LOW_PRIO` and `HIGH_PRIO`.
338 /// `core_id` defines the core, where the thread is located.
339 /// A negative value give the operating system the possibility
340 /// to select the core by its own.
341 #[inline(always)]
342 pub unsafe fn spawn(
343 	id: *mut Tid,
344 	func: extern "C" fn(usize),
345 	arg: usize,
346 	prio: u8,
347 	core_id: isize,
348 ) -> i32 {
349 	sys_spawn(id, func, arg, prio, core_id)
350 }
351 
352 /// spawn a new thread with user-specified stack size
353 ///
354 /// spawn2() starts a new thread. The new thread starts execution
355 /// by invoking `func(usize)`; `arg` is passed as the argument
356 /// to `func`. `prio` defines the priority of the new thread,
357 /// which can be between `LOW_PRIO` and `HIGH_PRIO`.
358 /// `core_id` defines the core, where the thread is located.
359 /// A negative value give the operating system the possibility
360 /// to select the core by its own.
361 /// In contrast to spawn(), spawn2() is able to define the
362 /// stack size.
363 #[inline(always)]
364 pub unsafe fn spawn2(
365 	func: extern "C" fn(usize),
366 	arg: usize,
367 	prio: u8,
368 	stack_size: usize,
369 	core_id: isize,
370 ) -> Tid {
371 	sys_spawn2(func, arg, prio, stack_size, core_id)
372 }
373 
374 /// join with a terminated thread
375 ///
376 /// The join() function waits for the thread specified by `id`
377 /// to terminate.
378 #[inline(always)]
379 pub unsafe fn join(id: Tid) -> i32 {
380 	sys_join(id)
381 }
382 
383 /// yield the processor
384 ///
385 /// causes the calling thread to relinquish the CPU. The thread
386 /// is moved to the end of the queue for its static priority.
387 #[inline(always)]
388 pub unsafe fn yield_now() {
389 	sys_yield()
390 }
391 
392 /// get current time
393 ///
394 /// The clock_gettime() functions allow the calling thread
395 /// to retrieve the value used by a clock which is specified
396 /// by `clock_id`.
397 ///
398 /// `CLOCK_REALTIME`: the system's real time clock,
399 /// expressed as the amount of time since the Epoch.
400 ///
401 /// `CLOCK_MONOTONIC`: clock that increments monotonically,
402 /// tracking the time since an arbitrary point
403 #[inline(always)]
404 pub unsafe fn clock_gettime(clock_id: u64, tp: *mut timespec) -> i32 {
405 	sys_clock_gettime(clock_id, tp)
406 }
407 
408 /// open and possibly create a file
409 ///
410 /// The open() system call opens the file specified by `name`.
411 /// If the specified file does not exist, it may optionally
412 /// be created by open().
413 #[inline(always)]
414 pub unsafe fn open(name: *const i8, flags: i32, mode: i32) -> i32 {
415 	sys_open(name, flags, mode)
416 }
417 
418 /// delete the file it refers to `name`
419 #[inline(always)]
420 pub unsafe fn unlink(name: *const i8) -> i32 {
421 	sys_unlink(name)
422 }
423