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" { 18 fn sys_secure_rand64() -> Option<u64>; 19 fn sys_secure_rand32() -> Option<u32>; 20 } 21 22 extern "C" { 23 fn sys_rand() -> u32; 24 fn sys_srand(seed: u32); 25 fn sys_get_processor_count() -> usize; 26 fn sys_malloc(size: usize, align: usize) -> *mut u8; 27 fn sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8; 28 fn sys_free(ptr: *mut u8, size: usize, align: usize); 29 fn sys_init_queue(ptr: usize) -> i32; 30 fn sys_notify(id: usize, count: i32) -> i32; 31 fn sys_add_queue(id: usize, timeout_ns: i64) -> i32; 32 fn sys_wait(id: usize) -> i32; 33 fn sys_destroy_queue(id: usize) -> i32; 34 fn sys_read(fd: i32, buf: *mut u8, len: usize) -> isize; 35 fn sys_write(fd: i32, buf: *const u8, len: usize) -> isize; 36 fn sys_close(fd: i32) -> i32; 37 fn sys_sem_init(sem: *mut *const c_void, value: u32) -> i32; 38 fn sys_sem_destroy(sem: *const c_void) -> i32; 39 fn sys_sem_post(sem: *const c_void) -> i32; 40 fn sys_sem_trywait(sem: *const c_void) -> i32; 41 fn sys_sem_timedwait(sem: *const c_void, ms: u32) -> i32; 42 fn sys_recmutex_init(recmutex: *mut *const c_void) -> i32; 43 fn sys_recmutex_destroy(recmutex: *const c_void) -> i32; 44 fn sys_recmutex_lock(recmutex: *const c_void) -> i32; 45 fn sys_recmutex_unlock(recmutex: *const c_void) -> i32; 46 fn sys_getpid() -> u32; 47 fn sys_exit(arg: i32) -> !; 48 fn sys_abort() -> !; 49 fn sys_usleep(usecs: u64); 50 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; 57 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; 64 fn sys_join(id: Tid) -> i32; 65 fn sys_yield(); 66 fn sys_clock_gettime(clock_id: u64, tp: *mut timespec) -> i32; 67 fn sys_open(name: *const i8, flags: i32, mode: i32) -> i32; 68 fn sys_unlink(name: *const i8) -> i32; 69 fn sys_network_init() -> i32; 70 fn sys_block_current_task(); 71 fn sys_wakeup_task(tid: Tid); 72 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 { 86 pub const fn into(self) -> u8 { 87 self.0 88 } 89 90 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 118 pub fn isatty(_fd: libc::c_int) -> bool { 119 false 120 } 121 122 /// initialize the network stack 123 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)] 168 pub unsafe fn get_processor_count() -> usize { 169 sys_get_processor_count() 170 } 171 172 #[doc(hidden)] 173 #[inline(always)] 174 pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 { 175 sys_malloc(size, align) 176 } 177 178 #[doc(hidden)] 179 #[inline(always)] 180 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)] 186 pub unsafe fn free(ptr: *mut u8, size: usize, align: usize) { 187 sys_free(ptr, size, align) 188 } 189 190 #[inline(always)] 191 pub unsafe fn notify(id: usize, count: i32) -> i32 { 192 sys_notify(id, count) 193 } 194 195 #[doc(hidden)] 196 #[inline(always)] 197 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)] 203 pub unsafe fn wait(id: usize) -> i32 { 204 sys_wait(id) 205 } 206 207 #[doc(hidden)] 208 #[inline(always)] 209 pub unsafe fn init_queue(id: usize) -> i32 { 210 sys_init_queue(id) 211 } 212 213 #[doc(hidden)] 214 #[inline(always)] 215 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)] 225 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)] 235 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)] 244 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)] 252 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)] 259 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)] 268 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)] 278 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)] 292 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)] 298 pub unsafe fn recmutex_init(recmutex: *mut *const c_void) -> i32 { 299 sys_recmutex_init(recmutex) 300 } 301 302 #[doc(hidden)] 303 #[inline(always)] 304 pub unsafe fn recmutex_destroy(recmutex: *const c_void) -> i32 { 305 sys_recmutex_destroy(recmutex) 306 } 307 308 #[doc(hidden)] 309 #[inline(always)] 310 pub unsafe fn recmutex_lock(recmutex: *const c_void) -> i32 { 311 sys_recmutex_lock(recmutex) 312 } 313 314 #[doc(hidden)] 315 #[inline(always)] 316 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)] 322 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)] 329 pub unsafe fn exit(arg: i32) -> ! { 330 sys_exit(arg) 331 } 332 333 /// cause abnormal termination 334 #[inline(always)] 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)] 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)] 358 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)] 380 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)] 395 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)] 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)] 420 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)] 430 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)] 436 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)] 446 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)] 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)] 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)] 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)] 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)] 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)] 488 pub unsafe fn get_priority() -> Priority { 489 Priority::from(sys_get_priority()) 490 } 491