diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c76e345bb7b64..a99227c55e3da 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1671,6 +1671,7 @@ supported_targets! { ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf), ("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf), ("riscv32im-unknown-none-elf", riscv32im_unknown_none_elf), + ("riscv32im-unknown-openvm-elf", riscv32im_unknown_openvm_elf), ("riscv32ima-unknown-none-elf", riscv32ima_unknown_none_elf), ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf), ("riscv32imc-esp-espidf", riscv32imc_esp_espidf), @@ -1975,6 +1976,7 @@ crate::target_spec_enum! { Nto = "nto", NuttX = "nuttx", OpenBsd = "openbsd", + Openvm = "openvm", Psp = "psp", Psx = "psx", Qurt = "qurt", diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_openvm_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_openvm_elf.rs new file mode 100644 index 0000000000000..b6296ae937c47 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_openvm_elf.rs @@ -0,0 +1,43 @@ +use crate::spec::{ + Arch, Cc, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, +}; + +pub(crate) fn target() -> Target { + Target { + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), + llvm_target: "riscv32".into(), + metadata: TargetMetadata { + description: Some("OpenVM zero-knowledge Virtual Machine (RV32IM ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), + }, + pointer_width: 32, + arch: Arch::RiscV32, + + options: TargetOptions { + os: Os::Openvm, + vendor: "unknown".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + cpu: "generic-rv32".into(), + + // We set atomic_width to 64 for compatibility with crates such as crossbeam, + // but this should never be triggered since compilation should always lower + // atomics and be single-threaded. + max_atomic_width: Some(64), + atomic_cas: true, + + features: "+m".into(), + llvm_abiname: "ilp32".into(), + executables: true, + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + singlethread: true, + ..Default::default() + }, + } +} diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml index ecf043ac7071c..781b791ba16dd 100644 --- a/library/panic_abort/Cargo.toml +++ b/library/panic_abort/Cargo.toml @@ -17,5 +17,5 @@ core = { path = "../rustc-std-workspace-core", package = "rustc-std-workspace-co [target.'cfg(target_os = "android")'.dependencies] libc = { version = "0.2", default-features = false } -[target.'cfg(any(target_os = "android", target_os = "zkvm"))'.dependencies] +[target.'cfg(any(target_os = "android", target_os = "zkvm", target_os = "openvm"))'.dependencies] alloc = { path = "../alloc" } diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index d1706b6525295..ecf89e82846bb 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -19,6 +19,9 @@ mod android; #[cfg(target_os = "zkvm")] mod zkvm; +#[cfg(target_os = "openvm")] +mod openvm; + use core::any::Any; use core::panic::PanicPayload; @@ -40,7 +43,10 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { unsafe { zkvm::zkvm_set_abort_message(_payload); } - + #[cfg(target_os = "openvm")] + unsafe { + openvm::openvm_set_abort_message(_payload); + } unsafe extern "Rust" { // This is defined in std::rt. #[rustc_std_internal_symbol] diff --git a/library/panic_abort/src/openvm.rs b/library/panic_abort/src/openvm.rs new file mode 100644 index 0000000000000..01d93ef59d9b2 --- /dev/null +++ b/library/panic_abort/src/openvm.rs @@ -0,0 +1,25 @@ +use alloc::string::String; +use core::panic::PanicPayload; + +// Forward the abort message to OpenVM's sys_panic. +pub(crate) unsafe fn openvm_set_abort_message(payload: &mut dyn PanicPayload) { + let payload = payload.get(); + let msg = match payload.downcast_ref::<&'static str>() { + Some(msg) => msg.as_bytes(), + None => match payload.downcast_ref::() { + Some(msg) => msg.as_bytes(), + None => &[], + }, + }; + if msg.is_empty() { + return; + } + + unsafe extern "C" { + fn sys_panic(msg_ptr: *const u8, len: usize) -> !; + } + + unsafe { + sys_panic(msg.as_ptr(), msg.len()); + } +} diff --git a/library/std/build.rs b/library/std/build.rs index bee28e88491d0..42f60d0119f74 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -54,6 +54,7 @@ fn main() { || target_os == "nuttx" || target_os == "cygwin" || target_os == "vexos" + || target_os == "openvm" // See src/bootstrap/src/core/build_steps/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() diff --git a/library/std/src/random.rs b/library/std/src/random.rs index 3994c5cfaf6f4..c14d8cb353c65 100644 --- a/library/std/src/random.rs +++ b/library/std/src/random.rs @@ -45,6 +45,7 @@ use crate::sys::random as sys; /// VxWorks | `randABytes` after waiting for `randSecure` to become ready /// WASI | [`random_get`](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#-random_getbuf-pointeru8-buf_len-size---result-errno) /// ZKVM | `sys_rand` +/// OpenVM | `sys_rand` /// /// Note that the sources used might change over time. /// diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs index f2f1d1c7feceb..828545e73b601 100644 --- a/library/std/src/sys/alloc/mod.rs +++ b/library/std/src/sys/alloc/mod.rs @@ -7,10 +7,13 @@ use crate::ptr; // add fast paths for low alignment values. #[allow(dead_code)] const MIN_ALIGN: usize = if cfg!(any( - all(target_arch = "riscv32", any(target_os = "espidf", target_os = "zkvm")), + all( + target_arch = "riscv32", + any(target_os = "espidf", target_os = "zkvm", target_os = "openvm") + ), all(target_arch = "xtensa", target_os = "espidf"), )) { - // The allocator on the esp-idf and zkvm platforms guarantees 4 byte alignment. + // The allocator on the esp-idf, zkvm, and openvm platforms guarantees 4 byte alignment. 4 } else if cfg!(any( target_arch = "x86", @@ -107,4 +110,7 @@ cfg_select! { target_os = "zkvm" => { mod zkvm; } + target_os = "openvm" => { + mod openvm; + } } diff --git a/library/std/src/sys/alloc/openvm.rs b/library/std/src/sys/alloc/openvm.rs new file mode 100644 index 0000000000000..a600cfa2220dd --- /dev/null +++ b/library/std/src/sys/alloc/openvm.rs @@ -0,0 +1,15 @@ +use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::sys::pal::abi; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + unsafe { abi::sys_alloc_aligned(layout.size(), layout.align()) } + } + + #[inline] + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { + // this allocator never deallocates memory + } +} diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index 5424d40a15883..3c4c43a490b43 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -53,6 +53,10 @@ cfg_select! { mod zkvm; pub use zkvm::*; } + target_os = "openvm" => { + mod openvm; + pub use openvm::*; + } _ => { mod unsupported; pub use unsupported::*; diff --git a/library/std/src/sys/args/openvm.rs b/library/std/src/sys/args/openvm.rs new file mode 100644 index 0000000000000..d26bf1eaff91f --- /dev/null +++ b/library/std/src/sys/args/openvm.rs @@ -0,0 +1,94 @@ +use crate::ffi::{OsStr, OsString}; +use crate::num::NonZero; +use crate::sync::OnceLock; +use crate::sys::pal::{WORD_SIZE, abi}; +use crate::{fmt, ptr, slice}; + +pub fn args() -> Args { + Args { iter: ARGS.get_or_init(|| get_args()).iter() } +} + +fn get_args() -> Vec<&'static OsStr> { + let argc = unsafe { abi::sys_argc() }; + let mut args = Vec::with_capacity(argc); + + for i in 0..argc { + // Get the size of the argument then the data. + let arg_len = unsafe { abi::sys_argv(ptr::null_mut(), 0, i) }; + + let arg_len_words = (arg_len + WORD_SIZE - 1) / WORD_SIZE; + let words = unsafe { abi::sys_alloc_words(arg_len_words) }; + + let arg_len2 = unsafe { abi::sys_argv(words, arg_len_words, i) }; + debug_assert_eq!(arg_len, arg_len2); + + let arg_bytes = unsafe { slice::from_raw_parts(words.cast(), arg_len) }; + args.push(unsafe { OsStr::from_encoded_bytes_unchecked(arg_bytes) }); + } + args +} + +static ARGS: OnceLock> = OnceLock::new(); + +pub struct Args { + iter: slice::Iter<'static, &'static OsStr>, +} + +impl !Send for Args {} +impl !Sync for Args {} + +impl fmt::Debug for Args { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.iter.as_slice().fmt(f) + } +} + +impl Iterator for Args { + type Item = OsString; + + fn next(&mut self) -> Option { + self.iter.next().map(|arg| arg.to_os_string()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.len() + } + + fn last(self) -> Option { + self.iter.last().map(|arg| arg.to_os_string()) + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_by(n) + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.iter.next_back().map(|arg| arg.to_os_string()) + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_back_by(n) + } +} + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs index 89856516b6dce..039dfe7afa92e 100644 --- a/library/std/src/sys/env/mod.rs +++ b/library/std/src/sys/env/mod.rs @@ -55,6 +55,10 @@ cfg_select! { mod zkvm; pub use zkvm::*; } + target_os = "openvm" => { + mod openvm; + pub use openvm::*; + } _ => { mod unsupported; pub use unsupported::*; diff --git a/library/std/src/sys/env/openvm.rs b/library/std/src/sys/env/openvm.rs new file mode 100644 index 0000000000000..93813c184a289 --- /dev/null +++ b/library/std/src/sys/env/openvm.rs @@ -0,0 +1,28 @@ +#[expect(dead_code)] +#[path = "unsupported.rs"] +mod unsupported_env; +pub use unsupported_env::{Env, env, setenv, unsetenv}; + +use crate::ffi::{OsStr, OsString}; +use crate::sys::os_str; +use crate::sys::pal::{WORD_SIZE, abi}; +use crate::sys_common::FromInner; + +pub fn getenv(varname: &OsStr) -> Option { + let varname = varname.as_encoded_bytes(); + let nbytes = + unsafe { abi::sys_getenv(crate::ptr::null_mut(), 0, varname.as_ptr(), varname.len()) }; + if nbytes == usize::MAX { + return None; + } + + let nwords = (nbytes + WORD_SIZE - 1) / WORD_SIZE; + let words = unsafe { abi::sys_alloc_words(nwords) }; + + let nbytes2 = unsafe { abi::sys_getenv(words, nwords, varname.as_ptr(), varname.len()) }; + debug_assert_eq!(nbytes, nbytes2); + + // Convert to OsString. + let u8s: &[u8] = unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, nbytes) }; + Some(OsString::from_inner(os_str::Buf { inner: u8s.to_vec() })) +} diff --git a/library/std/src/sys/env_consts.rs b/library/std/src/sys/env_consts.rs index 573f540483b1a..26de0527604c7 100644 --- a/library/std/src/sys/env_consts.rs +++ b/library/std/src/sys/env_consts.rs @@ -411,6 +411,17 @@ pub mod os { pub const EXE_EXTENSION: &str = "elf"; } +#[cfg(target_os = "openvm")] +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = "openvm"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".elf"; + pub const DLL_EXTENSION: &str = "elf"; + pub const EXE_SUFFIX: &str = ".elf"; + pub const EXE_EXTENSION: &str = "elf"; +} + // The fallback when none of the other gates match. #[else] pub mod os { diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index e11df38a8ee68..5275ad10340c8 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -85,6 +85,10 @@ cfg_select! { mod zkvm; pub use self::zkvm::*; } + target_os = "openvm" => { + mod openvm; + pub use self::openvm::*; + } _ => { mod unsupported; pub use self::unsupported::*; diff --git a/library/std/src/sys/pal/openvm/abi.rs b/library/std/src/sys/pal/openvm/abi.rs new file mode 100644 index 0000000000000..491fdb3c17897 --- /dev/null +++ b/library/std/src/sys/pal/openvm/abi.rs @@ -0,0 +1,35 @@ +//! ABI definitions for symbols exported by OpenVM. + +// We provide the ABI so that the OpenVM-specific implementations can be provided +// by linking the openvm crate without introducing the crate as a dependency here +#![allow(dead_code)] + +/// Standard IO file descriptors for use with sys_read and sys_write. +pub mod fileno { + pub const STDIN: u32 = 0; + pub const STDOUT: u32 = 1; + pub const STDERR: u32 = 2; + pub const JOURNAL: u32 = 3; +} + +unsafe extern "C" { + // Wrappers around syscalls provided by OpenVM: + pub fn sys_halt(); + pub fn sys_rand(recv_buf: *mut u32, words: usize); + pub fn sys_panic(msg_ptr: *const u8, len: usize) -> !; + pub fn sys_log(msg_ptr: *const u8, len: usize); + pub fn sys_read(fd: u32, recv_buf: *mut u8, nrequested: usize) -> usize; + pub fn sys_write(fd: u32, write_buf: *const u8, nbytes: usize); + pub fn sys_getenv( + recv_buf: *mut u32, + words: usize, + varname: *const u8, + varname_len: usize, + ) -> usize; + pub fn sys_argc() -> usize; + pub fn sys_argv(out_words: *mut u32, out_nwords: usize, arg_index: usize) -> usize; + + // Allocate memory from global HEAP. + pub fn sys_alloc_words(nwords: usize) -> *mut u32; + pub fn sys_alloc_aligned(nwords: usize, align: usize) -> *mut u8; +} diff --git a/library/std/src/sys/pal/openvm/mod.rs b/library/std/src/sys/pal/openvm/mod.rs new file mode 100644 index 0000000000000..bc128d8564e09 --- /dev/null +++ b/library/std/src/sys/pal/openvm/mod.rs @@ -0,0 +1,49 @@ +//! System bindings for the OpenVM platform +//! +//! This module contains the facade (aka platform-specific) implementations of +//! OS level functionality for OpenVM. +//! +//! This is all super highly experimental and not actually intended for +//! wide/production use yet, it's still all in the experimental category. This +//! will likely change over time. +#![forbid(unsafe_op_in_unsafe_fn)] + +pub const WORD_SIZE: usize = size_of::(); + +pub mod abi; +#[path = "../unsupported/os.rs"] +pub mod os; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +#[path = "../unsupported/time.rs"] +pub mod time; + +use crate::io as std_io; + +// SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. +pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} + +// SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. +pub unsafe fn cleanup() {} + +pub fn unsupported() -> std_io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> std_io::Error { + std_io::Error::UNSUPPORTED_PLATFORM +} + +pub fn is_interrupted(_code: i32) -> bool { + false +} + +pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { + crate::io::ErrorKind::Uncategorized +} + +pub fn abort_internal() -> ! { + core::intrinsics::abort(); +} diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index 91f72d0738790..116d12a5276c4 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -102,6 +102,10 @@ cfg_select! { mod zkvm; pub use zkvm::fill_bytes; } + target_os = "openvm" => { + mod openvm; + pub use openvm::fill_bytes; + } any( all(target_family = "wasm", target_os = "unknown"), target_os = "xous", diff --git a/library/std/src/sys/random/openvm.rs b/library/std/src/sys/random/openvm.rs new file mode 100644 index 0000000000000..4e8bef8265707 --- /dev/null +++ b/library/std/src/sys/random/openvm.rs @@ -0,0 +1,21 @@ +use crate::sys::pal::abi; + +pub fn fill_bytes(bytes: &mut [u8]) { + let (pre, words, post) = unsafe { bytes.align_to_mut::() }; + if !words.is_empty() { + unsafe { + abi::sys_rand(words.as_mut_ptr(), words.len()); + } + } + + let mut buf = [0u32; 2]; + let len = (pre.len() + post.len()).div_ceil(size_of::()); + if len != 0 { + unsafe { abi::sys_rand(buf.as_mut_ptr(), len) }; + } + + let buf = buf.map(u32::to_ne_bytes); + let buf = buf.as_flattened(); + pre.copy_from_slice(&buf[..pre.len()]); + post.copy_from_slice(&buf[pre.len()..pre.len() + post.len()]); +} diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs index d51ea9ad726b5..b3fbcc77b55e5 100644 --- a/library/std/src/sys/stdio/mod.rs +++ b/library/std/src/sys/stdio/mod.rs @@ -53,6 +53,10 @@ cfg_select! { mod zkvm; pub use zkvm::*; } + target_os = "openvm" => { + mod openvm; + pub use openvm::*; + } _ => { mod unsupported; pub use unsupported::*; diff --git a/library/std/src/sys/stdio/openvm.rs b/library/std/src/sys/stdio/openvm.rs new file mode 100644 index 0000000000000..84496ac937363 --- /dev/null +++ b/library/std/src/sys/stdio/openvm.rs @@ -0,0 +1,72 @@ +use crate::io::{self, BorrowedCursor}; +use crate::sys::pal::abi::{self, fileno}; + +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; + +impl Stdin { + pub const fn new() -> Stdin { + Stdin + } +} + +impl io::Read for Stdin { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + Ok(unsafe { abi::sys_read(fileno::STDIN, buf.as_mut_ptr(), buf.len()) }) + } + + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { + unsafe { + let n = abi::sys_read(fileno::STDIN, buf.as_mut().as_mut_ptr().cast(), buf.capacity()); + buf.advance(n); + } + Ok(()) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::sys_write(fileno::STDOUT, buf.as_ptr(), buf.len()) } + + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub const fn new() -> Stderr { + Stderr + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::sys_write(fileno::STDERR, buf.as_ptr(), buf.len()) } + + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +pub fn panic_output() -> Option { + Some(Stderr::new()) +} diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index e88011aa22dad..ca30fc8bfe236 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -28,6 +28,7 @@ cfg_select! { all(target_family = "wasm", not(target_feature = "atomics")), target_os = "uefi", target_os = "zkvm", + target_os = "openvm", target_os = "trusty", target_os = "vexos", ) => { @@ -98,6 +99,7 @@ pub(crate) mod guard { )), target_os = "uefi", target_os = "zkvm", + target_os = "openvm", target_os = "trusty", target_os = "vexos", ) => { diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 13b2b3d502c81..6ab0c4c5e707f 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -320,8 +320,10 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu // Prevent the usage of `Instant` in some cases: // - It's currently not supported for wasm targets without Emscripten nor WASI. // - It's currently not supported for zkvm targets. - let is_instant_unsupported = - (cfg!(target_family = "wasm") && cfg!(target_os = "unknown")) || cfg!(target_os = "zkvm"); + // - It's currently not supported for openvm targets. + let is_instant_unsupported = (cfg!(target_family = "wasm") && cfg!(target_os = "unknown")) + || cfg!(target_os = "zkvm") + || cfg!(target_os = "openvm"); let start_time = (!is_instant_unsupported).then(Instant::now); run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?; diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index d554807bbde70..4915fc33dd32a 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -580,7 +580,7 @@ pub fn run_test( // Emscripten can catch panics but other wasm targets cannot let ignore_because_no_process_support = desc.should_panic != ShouldPanic::No - && (cfg!(target_family = "wasm") || cfg!(target_os = "zkvm")) + && (cfg!(target_family = "wasm") || cfg!(target_os = "zkvm") || cfg!(target_os = "openvm")) && !cfg!(target_os = "emscripten"); if force_ignore || desc.ignore || ignore_because_no_process_support { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index a31eb0c1c8012..c459be9431a28 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -841,8 +841,8 @@ impl Build { features.insert("profiler"); } - // If zkvm target, generate memcpy, etc. - if target.contains("zkvm") { + // If zkvm or openvm target, generate memcpy, etc. + if target.contains("zkvm") || target.contains("openvm") { features.insert("compiler-builtins-mem"); } diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 832b5a69d47c4..65a2c77058404 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -111,6 +111,7 @@ - [riscv32e\*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md) - [riscv32i\*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md) + - [riscv32im-unknown-openvm-elf](platform-support/riscv32im-unknown-openvm-elf.md) - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md) - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d772702df76e2..ce49249ee185f 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -380,6 +380,7 @@ target | std | host | notes `riscv32gc-unknown-linux-gnu` | ✓ | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | ? | | RISC-V Linux (kernel 5.4, musl 1.2.5) [`riscv32im-risc0-zkvm-elf`](platform-support/riscv32im-risc0-zkvm-elf.md) | ? | | RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA) +[`riscv32im-unknown-openvm-elf`](platform-support/riscv32im-unknown-openvm-elf.md) | ? | | OpenVM zero-knowledge Virtual Machine (RV32IM ISA) [`riscv32ima-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32IMA ISA) [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imac-unknown-nuttx-elf`](platform-support/nuttx.md) | ✓ | | RISC-V 32bit with NuttX diff --git a/src/doc/rustc/src/platform-support/riscv32im-unknown-openvm-elf.md b/src/doc/rustc/src/platform-support/riscv32im-unknown-openvm-elf.md new file mode 100644 index 0000000000000..8b5c1cf80304a --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32im-unknown-openvm-elf.md @@ -0,0 +1,72 @@ +# `riscv32im-unknown-openvm-elf` + +**Tier: 3** + +Target for [OpenVM](https://github.com/openvm-org/openvm/) virtual machines with the RV32IM ISA and custom RISC-V extensions defined through OpenVM's extension framework. + +## Target maintainers + +[@jonathanpwang](https://github.com/jonathanpwang) +[@yi-sun](https://github.com/yi-sun) + +## Background + +This target is an execution environment to produce a verifiable cryptographic proof of execution of +a RISC‑V ELF binary and any output that the developer wishes to make public. +The execution environment is implemented as a virtual machine in software only. The target is not intended for bare metal hardware. The virtual machine may be extended to support custom RISC-V instruction sets, which may be invoked from Rust via the `asm!` macro. See the [OpenVM Book] for further documentation on the architecture and usage. + +We provide a cargo extension called [cargo-openvm] that provides tools for cross-compilation, execution, and generating cryptographic proofs of execution. + +## Requirements + +The target supports cross-compilation from any host and does not support host tools. It supports `alloc` with a +default allocator. Partial support for the Rust `std` library is provided using custom RISC-V instructions and requires the `openvm` crate with the `"std"` feature enabled. Further details and limitations of `std` support are documented [here](https://docs.openvm.dev/book/writing-apps/writing-a-program#rust-std-library-support). + +The target's execution environment is single-threaded, non-preemptive, and does not support +privileged instructions. At present, unaligned accesses are not supported and will result in execution traps. The binaries expect no operating system and can be thought +of as running on bare-metal. The target does not use `#[target_feature(...)]` or +`-C target-feature=` values. + +Binaries are expected to be ELF. + +Calling `extern "C"` uses the C calling convention outlined +in the [RISC-V specification]. + +## Building the target +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["riscv32im-unknown-openvm-elf"] +``` + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will need to do one of the following: +- Build Rust with the target enabled (see "Building the target" above) +- Build your own copy of `core` by passing args `-Zbuild-std=alloc,core,proc_macro,panic_abort,std -Zbuild-std-features=compiler-builtins-mem` +- Use `cargo openvm build` provided by the cargo extension [cargo-openvm]. + +The `cargo-openvm` utility is a command-line interface that calls `cargo` with the `build-std` flags above together with `rustc` flags `-C passes=lower-atomic -C link-arg=-Ttext=` to map text to the appropriate location. The text start (presently `0x0020_0800`) must be set to start above the stack top, and heap begins right after the text. The utility also includes the `rustc` flag `--cfg getrandom_backend="custom"` to enable a custom backend for the `getrandom` crate. + +## Testing + +Note: this target is implemented as a software virtual machine; there is no hardware implementation. + +Guest programs cross-compiled to the target must be run on the host inside OpenVM virtual machines, which are software emulators. The most practical way to do this is via either the [cargo-openvm] command-line interface or the [OpenVM SDK]. + +The target currently does not support running the Rust test suite. + +## Cross-compilation toolchains and C code + +Compatible C code can be built for this target on any compiler that has a RV32IM +target. On clang and ld.lld linker, it can be generated using the +`-march=rv32im`, `-mabi=ilp32` with llvm features flag `features=+m` and llvm +target `riscv32-unknown-none`. + +[RISC-V specification]: https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf +[OpenVM]: https://github.com/openvm-org/openvm/ +[OpenVM Book]: https://docs.openvm.dev/book/ +[OpenVM SDK]: https://docs.openvm.dev/book/advanced-usage/sdk +[cargo-openvm]: https://docs.openvm.dev/book/getting-started/install diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index 94649dde47361..60bc19d574db0 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // be kept in sync. let os = &this.tcx.sess.target.os; let max_fundamental_align = match &this.tcx.sess.target.arch { - Arch::RiscV32 if matches!(os, Os::EspIdf | Os::Zkvm) => 4, + Arch::RiscV32 if matches!(os, Os::EspIdf | Os::Zkvm | Os::Openvm) => 4, Arch::Xtensa if matches!(os, Os::EspIdf) => 4, Arch::X86 | Arch::Arm diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index 324c7fc9da4ee..7913ec97e202b 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -457,6 +457,9 @@ //@ revisions: riscv32im_unknown_none_elf //@ [riscv32im_unknown_none_elf] compile-flags: --target riscv32im-unknown-none-elf //@ [riscv32im_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32im_unknown_openvm_elf +//@ [riscv32im_unknown_openvm_elf] compile-flags: --target riscv32im-unknown-openvm-elf +//@ [riscv32im_unknown_openvm_elf] needs-llvm-components: riscv //@ revisions: riscv32ima_unknown_none_elf //@ [riscv32ima_unknown_none_elf] compile-flags: --target riscv32ima-unknown-none-elf //@ [riscv32ima_unknown_none_elf] needs-llvm-components: riscv diff --git a/tests/ui/check-cfg/cfg-crate-features.stderr b/tests/ui/check-cfg/cfg-crate-features.stderr index 242883995488e..aeb4096486854 100644 --- a/tests/ui/check-cfg/cfg-crate-features.stderr +++ b/tests/ui/check-cfg/cfg-crate-features.stderr @@ -24,7 +24,7 @@ warning: unexpected `cfg` condition value: `does_not_exist` LL | #![cfg(not(target(os = "does_not_exist")))] | ^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qurt`, `redox`, `rtems`, `solaris`, and `solid_asp3` and 14 more + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `openvm`, `psp`, `psx`, `qurt`, `redox`, `rtems`, and `solaris` and 15 more = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index efa0a7f4af9ac..ed69f06ba8909 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -201,7 +201,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `openvm`, `psp`, `psx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -274,7 +274,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `openvm`, `psp`, `psx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: 28 warnings emitted