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