forked from able/libwasm
add new syscalls; cross platform abstraction for io and rng seeding
This commit is contained in:
parent
32970613cc
commit
be26b9e4d5
16
Cargo.toml
16
Cargo.toml
|
@ -6,3 +6,19 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
once_cell = { version = "1.10.0", default-features = false, features = ["std"], optional = true }
|
||||
rand_core = { version = "0.6", default-features = false, optional = true }
|
||||
rand_pcg = { version = "0.3.1", default-features = false, optional = true }
|
||||
|
||||
[target.'cfg(not(ableOS))'.dependencies]
|
||||
rand_core = { version = "0.6", default-features = false, optional = true, features = ["getrandom"] }
|
||||
|
||||
|
||||
[features]
|
||||
default = ["rng", "pcg_rng", "io"]
|
||||
# Controls availability of the `rand` module, which provides seeding for `rand` (the crate) RNGs.
|
||||
rng = ["dep:rand_core"]
|
||||
# Controls the availability of `obtain_rng`, which internally uses `rand_pcg`.
|
||||
pcg_rng = ["rng", "dep:rand_pcg"]
|
||||
# Controls the availability of the cross platform `io` module.
|
||||
io = ["dep:once_cell"]
|
||||
|
|
144
src/io.rs
Normal file
144
src/io.rs
Normal file
|
@ -0,0 +1,144 @@
|
|||
//! This module provides cross platform I/O facilities. It takes inspiration from the Rust `std::io` module,
|
||||
//! and uses that for platform support outside of ableOS.
|
||||
//! One day, we might hope for this module to be superseded by real `std` support for ableOS.
|
||||
use ::std::io::{self, Read, BufRead, BufReader, IoSliceMut};
|
||||
|
||||
/// Print a string to the console.
|
||||
fn print(x: &str) {
|
||||
#[cfg(ableOS)] {
|
||||
extern "C" {
|
||||
fn print_char(x: u32);
|
||||
}
|
||||
fn print_byte(x: u8) {
|
||||
unsafe { print_char(x as u32) }
|
||||
}
|
||||
for b in x.bytes() {
|
||||
print_byte(b);
|
||||
}
|
||||
}
|
||||
#[cfg(not(ableOS))] {
|
||||
print!("{}", x)
|
||||
}
|
||||
}
|
||||
/// Like [`print`], but starts a new line after.
|
||||
pub fn println(x: &str) {
|
||||
print(x);
|
||||
print("\n");
|
||||
}
|
||||
|
||||
/// Like [`println`], but meant to print to a standard error output.
|
||||
pub fn eprintln(x: &str) {
|
||||
#[cfg(ableOS)] {
|
||||
println(x);
|
||||
}
|
||||
#[cfg(not(ableOS))] {
|
||||
eprintln!("{}", x)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(ableOS)]
|
||||
static STDIN: ::once_cell::sync::Lazy<::std::sync::Mutex<BufReader<AbleStdinRaw>>> = ::once_cell::sync::Lazy::new(|| {
|
||||
::std::sync::Mutex::new(BufReader::new(AbleStdinRaw))
|
||||
});
|
||||
|
||||
#[cfg(ableOS)]
|
||||
struct AbleStdinRaw;
|
||||
#[cfg(ableOS)]
|
||||
impl Read for AbleStdinRaw {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
// TODO: detect EOF
|
||||
loop {
|
||||
let chr = unsafe { crate::syscalls::get_input() };
|
||||
if chr != 0 {
|
||||
break Ok(char::from_u32(chr as u32).unwrap().encode_utf8(buf).len())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle to the standard input stream of the process.
|
||||
/// See [`Stdin`](::std::io::Stdin) for roughly how this should be treated.
|
||||
pub struct Stdin {
|
||||
#[cfg(ableOS)]
|
||||
inner: &'static ::std::sync::Mutex<BufReader<AbleStdinRaw>>,
|
||||
#[cfg(not(ableOS))]
|
||||
inner: io::Stdin,
|
||||
}
|
||||
impl Stdin {
|
||||
pub fn lock(&self) -> StdinLock<'_> {
|
||||
#[cfg(ableOS)] {
|
||||
StdinLock {
|
||||
inner: self.inner.lock().unwrap()
|
||||
}
|
||||
}
|
||||
#[cfg(not(ableOS))] {
|
||||
StdinLock {
|
||||
inner: self.inner.lock(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A locked reference to the [`Stdin`] handle.
|
||||
/// See [`StdinLock`](::std::io::StdinLock) for roughly how this should be treated.
|
||||
pub struct StdinLock<'a> {
|
||||
#[cfg(ableOS)]
|
||||
inner: ::std::sync::MutexGuard<'a, BufReader<AbleStdinRaw>>,
|
||||
#[cfg(not(ableOS))]
|
||||
inner: io::StdinLock<'a>,
|
||||
}
|
||||
|
||||
impl<'a> BufRead for StdinLock<'_> {
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
||||
self.inner.fill_buf()
|
||||
}
|
||||
|
||||
fn consume(&mut self, n: usize) {
|
||||
self.inner.consume(n)
|
||||
}
|
||||
|
||||
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.inner.read_until(byte, buf)
|
||||
}
|
||||
|
||||
fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||
self.inner.read_line(buf)
|
||||
}
|
||||
}
|
||||
impl Read for StdinLock<'_> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.inner.read(buf)
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.inner.read_vectored(bufs)
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.inner.read_to_end(buf)
|
||||
}
|
||||
|
||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||
self.inner.read_to_string(buf)
|
||||
}
|
||||
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
self.inner.read_exact(buf)
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new handle to the standard input of the current process.
|
||||
/// Each handle returned is a reference to a shared global buffer whose access is synchronized via a mutex.
|
||||
/// If you need more explicit control over locking, see the [`Stdin::lock`] method.
|
||||
pub fn stdin() -> Stdin {
|
||||
#[cfg(ableOS)] {
|
||||
Stdin {
|
||||
inner: &STDIN
|
||||
}
|
||||
}
|
||||
#[cfg(not(ableOS))] {
|
||||
Stdin {
|
||||
inner: ::std::io::stdin(),
|
||||
}
|
||||
}
|
||||
}
|
19
src/lib.rs
19
src/lib.rs
|
@ -1,13 +1,22 @@
|
|||
#![no_std]
|
||||
//! The base crate for writing guest programs to run on ableOS.
|
||||
//!
|
||||
//! ableOS is not a target known to rustc, and so we rely on a general `--cfg` switch
|
||||
//! to control the use of ableOS target specific code when underlying the portable
|
||||
//! abstractions defined in this crate.
|
||||
//!
|
||||
//! To target ableOS, set `cfg(ableOS)` and `--target=wasm32-unknown-unknown`.
|
||||
//! ```text
|
||||
//! RUSTFLAGS='--cfg=ableOS' cargo build --target=wasm32-unknown-unknown
|
||||
//! ```
|
||||
|
||||
#[macro_use]
|
||||
pub mod logger;
|
||||
pub mod driver;
|
||||
pub mod process;
|
||||
pub mod syscalls;
|
||||
#[cfg(feature = "io")]
|
||||
pub mod io;
|
||||
#[cfg(feature = "rng")]
|
||||
pub mod rand;
|
||||
|
||||
pub use core::*;
|
||||
|
||||
extern "C" {
|
||||
pub fn get_random() -> u32;
|
||||
}
|
||||
|
|
21
src/rand.rs
Normal file
21
src/rand.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use ::rand_core::SeedableRng;
|
||||
|
||||
/// Seed an RNG with system provided randomness.
|
||||
pub fn seed_rng<R: SeedableRng>() -> R {
|
||||
#[cfg(ableOS)] {
|
||||
let seed = unsafe {
|
||||
let seed_a = crate::syscalls::get_random();
|
||||
let seed_b = crate::syscalls::get_random();
|
||||
(seed_a as u64) << 32 | seed_b as u64
|
||||
};
|
||||
R::seed_from_u64(seed)
|
||||
}
|
||||
#[cfg(not(ableOS))] {
|
||||
R::from_entropy()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "pcg_rng")]
|
||||
pub fn obtain_rng() -> impl ::rand_core::RngCore {
|
||||
seed_rng::<::rand_pcg::Pcg32>()
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
#![deny(missing_docs)]
|
||||
//! The module of syscalls.
|
||||
//! This module provides declarations for all host provided functions.
|
||||
|
||||
use crate::process::{signals::Signals, PID};
|
||||
|
||||
pub mod file_calls;
|
||||
pub mod time_calls;
|
||||
|
||||
#[no_mangle]
|
||||
/// All system calls are defined here.
|
||||
extern "C" {
|
||||
|
||||
|
@ -21,4 +20,11 @@ extern "C" {
|
|||
/// A temporary function to test the syscall interface
|
||||
pub fn add(a: u32, b: u32) -> u32;
|
||||
|
||||
// TODO: ascertain whether the ableOS host provides randomness good enough for CSPRNGs
|
||||
/// The ableOS host provides entropy usable for seeding PRNGs.
|
||||
pub fn get_random() -> u32;
|
||||
|
||||
// This currently has very x86 specific semantics.
|
||||
/// Pops a byte from the key buffer.
|
||||
pub fn get_input() -> i32;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue