Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d0516ea

Browse files
SchmErikflaubshkoonategraf
committedNov 16, 2023
zkvm: add partial std support
Co-authored-by: Frank Laub <[email protected]> Co-authored-by: nils <[email protected]> Co-authored-by: Victor Graf <[email protected]>
1 parent 6954a67 commit d0516ea

File tree

11 files changed

+428
-5
lines changed

11 files changed

+428
-5
lines changed
 

‎library/std/build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ fn main() {
3535
|| target.contains("xous")
3636
|| target.contains("hurd")
3737
|| target.contains("uefi")
38+
|| target.contains("zkvm")
3839
// See src/bootstrap/synthetic_targets.rs
3940
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
4041
{

‎library/std/src/sys/common/alloc.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::ptr;
1717
target_arch = "asmjs",
1818
target_arch = "wasm32",
1919
target_arch = "hexagon",
20-
all(target_arch = "riscv32", not(target_os = "espidf")),
20+
all(target_arch = "riscv32", not(any(target_os = "espidf", target_os = "zkvm"))),
2121
all(target_arch = "xtensa", not(target_os = "espidf")),
2222
))]
2323
pub const MIN_ALIGN: usize = 8;
@@ -33,11 +33,11 @@ pub const MIN_ALIGN: usize = 8;
3333
target_arch = "wasm64",
3434
))]
3535
pub const MIN_ALIGN: usize = 16;
36-
// The allocator on the esp-idf platform guarantees 4 byte alignment.
37-
#[cfg(any(
38-
all(target_arch = "riscv32", target_os = "espidf"),
36+
// The allocator on the esp-idf and zkvm platforms guarantee 4 byte alignment.
37+
#[cfg(all(any(
38+
all(target_arch = "riscv32", any(target_os = "espidf", target_os = "zkvm")),
3939
all(target_arch = "xtensa", target_os = "espidf"),
40-
))]
40+
)))]
4141
pub const MIN_ALIGN: usize = 4;
4242

4343
pub unsafe fn realloc_fallback(

‎library/std/src/sys/zkvm/abi.rs

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//! ABI definitions for symbols exported by risc0-zkvm-platform.
2+
3+
// Included here so we don't have to depend on risc0-zkvm-platform.
4+
//
5+
// FIXME: Should we move this to the "libc" crate? It seems like other
6+
// architectures put a lot of this kind of stuff there. But there's
7+
// currently no risc0 fork of the libc crate, so we'd either have to
8+
// fork it or upstream it.
9+
10+
#![allow(dead_code)]
11+
pub const DIGEST_WORDS: usize = 8;
12+
13+
/// Standard IO file descriptors for use with sys_read and sys_write.
14+
pub mod fileno {
15+
pub const STDIN: u32 = 0;
16+
pub const STDOUT: u32 = 1;
17+
pub const STDERR: u32 = 2;
18+
pub const JOURNAL: u32 = 3;
19+
}
20+
21+
extern "C" {
22+
// Wrappers around syscalls provided by risc0-zkvm-platform:
23+
pub fn sys_halt();
24+
pub fn sys_output(output_id: u32, output_value: u32);
25+
pub fn sys_sha_compress(
26+
out_state: *mut [u32; DIGEST_WORDS],
27+
in_state: *const [u32; DIGEST_WORDS],
28+
block1_ptr: *const [u32; DIGEST_WORDS],
29+
block2_ptr: *const [u32; DIGEST_WORDS],
30+
);
31+
pub fn sys_sha_buffer(
32+
out_state: *mut [u32; DIGEST_WORDS],
33+
in_state: *const [u32; DIGEST_WORDS],
34+
buf: *const u8,
35+
count: u32,
36+
);
37+
pub fn sys_rand(recv_buf: *mut u32, words: usize);
38+
pub fn sys_panic(msg_ptr: *const u8, len: usize) -> !;
39+
pub fn sys_log(msg_ptr: *const u8, len: usize);
40+
pub fn sys_cycle_count() -> usize;
41+
pub fn sys_read(fd: u32, recv_buf: *mut u8, nrequested: usize) -> usize;
42+
pub fn sys_write(fd: u32, write_buf: *const u8, nbytes: usize);
43+
pub fn sys_getenv(
44+
recv_buf: *mut u32,
45+
words: usize,
46+
varname: *const u8,
47+
varname_len: usize,
48+
) -> usize;
49+
pub fn sys_argc() -> usize;
50+
pub fn sys_argv(out_words: *mut u32, out_nwords: usize, arg_index: usize) -> usize;
51+
52+
// Allocate memory from global HEAP.
53+
pub fn sys_alloc_words(nwords: usize) -> *mut u32;
54+
pub fn sys_alloc_aligned(nwords: usize, align: usize) -> *mut u8;
55+
}

‎library/std/src/sys/zkvm/alloc.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use super::abi;
2+
use crate::alloc::{GlobalAlloc, Layout, System};
3+
4+
#[stable(feature = "alloc_system_type", since = "1.28.0")]
5+
unsafe impl GlobalAlloc for System {
6+
#[inline]
7+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
8+
abi::sys_alloc_aligned(layout.size(), layout.align())
9+
}
10+
11+
#[inline]
12+
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
13+
// this allocator never deallocates memory
14+
}
15+
}

‎library/std/src/sys/zkvm/args.rs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use super::{abi, WORD_SIZE};
2+
use crate::ffi::OsString;
3+
use crate::fmt;
4+
use crate::sys_common::FromInner;
5+
6+
pub struct Args {
7+
i_forward: usize,
8+
i_back: usize,
9+
count: usize,
10+
}
11+
12+
pub fn args() -> Args {
13+
let count = unsafe { abi::sys_argc() };
14+
Args { i_forward: 0, i_back: 0, count }
15+
}
16+
17+
impl Args {
18+
/// Use sys_argv to get the arg at the requested index. Does not check that i is less than argc
19+
/// and will not return if the index is out of bounds.
20+
fn argv(i: usize) -> OsString {
21+
let arg_len = unsafe { abi::sys_argv(crate::ptr::null_mut(), 0, i) };
22+
23+
let arg_len_words = (arg_len + WORD_SIZE - 1) / WORD_SIZE;
24+
let words = unsafe { abi::sys_alloc_words(arg_len_words) };
25+
26+
let arg_len2 = unsafe { abi::sys_argv(words, arg_len_words, i) };
27+
debug_assert_eq!(arg_len, arg_len2);
28+
29+
// Convert to OsString.
30+
//
31+
// FIXME: We can probably get rid of the extra copy here if we
32+
// reimplement "os_str" instead of just using the generic unix
33+
// "os_str".
34+
let arg_bytes: &[u8] =
35+
unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, arg_len) };
36+
OsString::from_inner(super::os_str::Buf { inner: arg_bytes.to_vec() })
37+
}
38+
}
39+
40+
impl fmt::Debug for Args {
41+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42+
f.debug_list().finish()
43+
}
44+
}
45+
46+
impl Iterator for Args {
47+
type Item = OsString;
48+
49+
fn next(&mut self) -> Option<OsString> {
50+
if self.i_forward >= self.count - self.i_back {
51+
None
52+
} else {
53+
let arg = Self::argv(self.i_forward);
54+
self.i_forward += 1;
55+
Some(arg)
56+
}
57+
}
58+
59+
fn size_hint(&self) -> (usize, Option<usize>) {
60+
(self.count, Some(self.count))
61+
}
62+
}
63+
64+
impl ExactSizeIterator for Args {
65+
fn len(&self) -> usize {
66+
self.count
67+
}
68+
}
69+
70+
impl DoubleEndedIterator for Args {
71+
fn next_back(&mut self) -> Option<OsString> {
72+
if self.i_back >= self.count - self.i_forward {
73+
None
74+
} else {
75+
let arg = Self::argv(self.count - 1 - self.i_back);
76+
self.i_back += 1;
77+
Some(arg)
78+
}
79+
}
80+
}

‎library/std/src/sys/zkvm/env.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
pub mod os {
2+
pub const FAMILY: &str = "";
3+
pub const OS: &str = "";
4+
pub const DLL_PREFIX: &str = "";
5+
pub const DLL_SUFFIX: &str = ".elf";
6+
pub const DLL_EXTENSION: &str = "elf";
7+
pub const EXE_SUFFIX: &str = ".elf";
8+
pub const EXE_EXTENSION: &str = "elf";
9+
}

‎library/std/src/sys/zkvm/mod.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//! System bindings for the risc0 zkvm platform
2+
//!
3+
//! This module contains the facade (aka platform-specific) implementations of
4+
//! OS level functionality for zkvm.
5+
//!
6+
//! This is all super highly experimental and not actually intended for
7+
//! wide/production use yet, it's still all in the experimental category. This
8+
//! will likely change over time.
9+
10+
const WORD_SIZE: usize = core::mem::size_of::<u32>();
11+
12+
pub mod alloc;
13+
#[path = "../zkvm/args.rs"]
14+
pub mod args;
15+
#[path = "../unix/cmath.rs"]
16+
pub mod cmath;
17+
pub mod env;
18+
#[path = "../unsupported/fs.rs"]
19+
pub mod fs;
20+
#[path = "../unsupported/io.rs"]
21+
pub mod io;
22+
#[path = "../unsupported/net.rs"]
23+
pub mod net;
24+
#[path = "../unsupported/once.rs"]
25+
pub mod once;
26+
pub mod os;
27+
#[path = "../unix/os_str.rs"]
28+
pub mod os_str;
29+
#[path = "../unix/path.rs"]
30+
pub mod path;
31+
#[path = "../unsupported/pipe.rs"]
32+
pub mod pipe;
33+
#[path = "../unsupported/process.rs"]
34+
pub mod process;
35+
pub mod stdio;
36+
pub mod thread_local_key;
37+
#[path = "../unsupported/time.rs"]
38+
pub mod time;
39+
40+
#[path = "../unsupported/locks/mod.rs"]
41+
pub mod locks;
42+
#[path = "../unsupported/thread.rs"]
43+
pub mod thread;
44+
45+
#[path = "../unsupported/common.rs"]
46+
#[deny(unsafe_op_in_unsafe_fn)]
47+
mod common;
48+
pub use common::*;
49+
50+
mod abi;

‎library/std/src/sys/zkvm/os.rs

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use super::{abi, unsupported, WORD_SIZE};
2+
use crate::error::Error as StdError;
3+
use crate::ffi::{OsStr, OsString};
4+
use crate::fmt;
5+
use crate::io;
6+
use crate::marker::PhantomData;
7+
use crate::path::{self, PathBuf};
8+
use crate::sys_common::FromInner;
9+
10+
pub fn errno() -> i32 {
11+
0
12+
}
13+
14+
pub fn error_string(_errno: i32) -> String {
15+
"operation successful".to_string()
16+
}
17+
18+
pub fn getcwd() -> io::Result<PathBuf> {
19+
unsupported()
20+
}
21+
22+
pub fn chdir(_: &path::Path) -> io::Result<()> {
23+
unsupported()
24+
}
25+
26+
pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);
27+
28+
pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
29+
panic!("unsupported")
30+
}
31+
32+
impl<'a> Iterator for SplitPaths<'a> {
33+
type Item = PathBuf;
34+
fn next(&mut self) -> Option<PathBuf> {
35+
self.0
36+
}
37+
}
38+
39+
#[derive(Debug)]
40+
pub struct JoinPathsError;
41+
42+
pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
43+
where
44+
I: Iterator<Item = T>,
45+
T: AsRef<OsStr>,
46+
{
47+
Err(JoinPathsError)
48+
}
49+
50+
impl fmt::Display for JoinPathsError {
51+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52+
"not supported on this platform yet".fmt(f)
53+
}
54+
}
55+
56+
impl StdError for JoinPathsError {
57+
#[allow(deprecated)]
58+
fn description(&self) -> &str {
59+
"not supported on this platform yet"
60+
}
61+
}
62+
63+
pub fn current_exe() -> io::Result<PathBuf> {
64+
unsupported()
65+
}
66+
67+
pub struct Env(!);
68+
69+
impl Iterator for Env {
70+
type Item = (OsString, OsString);
71+
fn next(&mut self) -> Option<(OsString, OsString)> {
72+
self.0
73+
}
74+
}
75+
76+
pub fn env() -> Env {
77+
panic!("not supported on this platform")
78+
}
79+
80+
pub fn getenv(varname: &OsStr) -> Option<OsString> {
81+
let varname = varname.bytes();
82+
let nbytes =
83+
unsafe { abi::sys_getenv(crate::ptr::null_mut(), 0, varname.as_ptr(), varname.len()) };
84+
if nbytes == usize::MAX {
85+
return None;
86+
}
87+
88+
let nwords = (nbytes + WORD_SIZE - 1) / WORD_SIZE;
89+
let words = unsafe { abi::sys_alloc_words(nwords) };
90+
91+
let nbytes2 = unsafe { abi::sys_getenv(words, nwords, varname.as_ptr(), varname.len()) };
92+
debug_assert_eq!(nbytes, nbytes2);
93+
94+
// Convert to OsString.
95+
//
96+
// FIXME: We can probably get rid of the extra copy here if we
97+
// reimplement "os_str" instead of just using the generic unix
98+
// "os_str".
99+
let u8s: &[u8] = unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, nbytes) };
100+
Some(OsString::from_inner(super::os_str::Buf { inner: u8s.to_vec() }))
101+
}
102+
103+
pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
104+
Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
105+
}
106+
107+
pub fn unsetenv(_: &OsStr) -> io::Result<()> {
108+
Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
109+
}
110+
111+
pub fn temp_dir() -> PathBuf {
112+
panic!("no filesystem on this platform")
113+
}
114+
115+
pub fn home_dir() -> Option<PathBuf> {
116+
None
117+
}
118+
119+
pub fn exit(_code: i32) -> ! {
120+
crate::intrinsics::abort()
121+
}
122+
123+
pub fn getpid() -> u32 {
124+
panic!("no pids on this platform")
125+
}

‎library/std/src/sys/zkvm/stdio.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use super::{abi, abi::fileno};
2+
use crate::io;
3+
4+
pub struct Stdin;
5+
pub struct Stdout;
6+
pub struct Stderr;
7+
8+
impl Stdin {
9+
pub const fn new() -> Stdin {
10+
Stdin
11+
}
12+
}
13+
14+
impl io::Read for Stdin {
15+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
16+
Ok(unsafe { abi::sys_read(fileno::STDIN, buf.as_mut_ptr(), buf.len()) })
17+
}
18+
}
19+
20+
impl Stdout {
21+
pub const fn new() -> Stdout {
22+
Stdout
23+
}
24+
}
25+
26+
impl io::Write for Stdout {
27+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
28+
unsafe { abi::sys_write(fileno::STDOUT, buf.as_ptr(), buf.len()) }
29+
30+
Ok(buf.len())
31+
}
32+
33+
fn flush(&mut self) -> io::Result<()> {
34+
Ok(())
35+
}
36+
}
37+
38+
impl Stderr {
39+
pub const fn new() -> Stderr {
40+
Stderr
41+
}
42+
}
43+
44+
impl io::Write for Stderr {
45+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
46+
unsafe { abi::sys_write(fileno::STDERR, buf.as_ptr(), buf.len()) }
47+
48+
Ok(buf.len())
49+
}
50+
51+
fn flush(&mut self) -> io::Result<()> {
52+
Ok(())
53+
}
54+
}
55+
56+
pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
57+
58+
pub fn is_ebadf(_err: &io::Error) -> bool {
59+
true
60+
}
61+
62+
pub fn panic_output() -> Option<impl io::Write> {
63+
Some(Stderr::new())
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use crate::alloc::{alloc, Layout};
2+
3+
pub type Key = usize;
4+
5+
#[inline]
6+
pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
7+
alloc(Layout::new::<*mut u8>()) as _
8+
}
9+
10+
#[inline]
11+
pub unsafe fn set(key: Key, value: *mut u8) {
12+
let key: *mut *mut u8 = core::ptr::from_exposed_addr_mut(key);
13+
*key = value;
14+
}
15+
16+
#[inline]
17+
pub unsafe fn get(key: Key) -> *mut u8 {
18+
let key: *mut *mut u8 = core::ptr::from_exposed_addr_mut(key);
19+
*key
20+
}
21+
22+
#[inline]
23+
pub unsafe fn destroy(_key: Key) {}

‎library/std/src/sys_common/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ cfg_if::cfg_if! {
4545
cfg_if::cfg_if! {
4646
if #[cfg(any(target_os = "l4re",
4747
target_os = "uefi",
48+
target_os = "zkvm",
4849
feature = "restricted-std",
4950
all(target_family = "wasm", not(target_os = "emscripten")),
5051
target_os = "xous",

0 commit comments

Comments
 (0)
Please sign in to comment.