From 53db5a54bf2618def5096590afa9b282d7f09521 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Thu, 5 Dec 2024 19:14:37 +0800 Subject: [PATCH 01/44] Hints in linker --- ceno_rt/ceno_link.x | 7 +++++++ ceno_rt/memory.x | 2 ++ ceno_rt/src/lib.rs | 2 ++ 3 files changed, 11 insertions(+) diff --git a/ceno_rt/ceno_link.x b/ceno_rt/ceno_link.x index 00b2ea282..2747b8109 100644 --- a/ceno_rt/ceno_link.x +++ b/ceno_rt/ceno_link.x @@ -1,5 +1,6 @@ _stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK); +_hints_start = ORIGIN(REGION_HINTS); SECTIONS { @@ -34,4 +35,10 @@ SECTIONS . = ALIGN(4); _sheap = .; } > RAM + + /* Define a section for runtime-populated EEPROM-like HINTS data */ + .hints (NOLOAD) : ALIGN(4) + { + *(.hints .hints.*); + } > HINTS } diff --git a/ceno_rt/memory.x b/ceno_rt/memory.x index 712de56cd..7c2a2538b 100644 --- a/ceno_rt/memory.x +++ b/ceno_rt/memory.x @@ -2,6 +2,7 @@ MEMORY { RAM : ORIGIN = 0x80000000, LENGTH = 1024M ROM : ORIGIN = 0x20000000, LENGTH = 16M + HINTS: ORIGIN = 0x40000000, LENGTH = 1024M } REGION_ALIAS("REGION_TEXT", ROM); @@ -10,3 +11,4 @@ REGION_ALIAS("REGION_DATA", RAM); REGION_ALIAS("REGION_BSS", RAM); REGION_ALIAS("REGION_HEAP", RAM); REGION_ALIAS("REGION_STACK", RAM); +REGION_ALIAS("REGION_HINTS", HINTS); diff --git a/ceno_rt/src/lib.rs b/ceno_rt/src/lib.rs index 8de456c41..9945057ec 100644 --- a/ceno_rt/src/lib.rs +++ b/ceno_rt/src/lib.rs @@ -94,4 +94,6 @@ extern "C" { static _stack_start: u8; // The address of this variable is the start of the heap (growing upwards). static _sheap: u8; + // The address of this variable is the start of the hints ROM. + static _hints_start: u8; } From 612befbda24679ab71ef63a38380fd84c7683205 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 6 Dec 2024 14:14:10 +0800 Subject: [PATCH 02/44] Snapshot --- Cargo.lock | 139 ++++++++++++++++++++++ Cargo.toml | 7 +- ceno_host/Cargo.toml | 12 ++ ceno_host/src/lib.rs | 250 +++++++++++++++++++++++++++++++++++++++ ceno_rt/Cargo.toml | 4 + ceno_rt/src/allocator.rs | 2 + ceno_rt/src/lib.rs | 5 + ceno_rt/src/mmio.rs | 109 +++++++++++++++++ examples/Cargo.lock | 136 +++++++++++++++++++++ 9 files changed, 661 insertions(+), 3 deletions(-) create mode 100644 ceno_host/Cargo.toml create mode 100644 ceno_host/src/lib.rs create mode 100644 ceno_rt/src/mmio.rs diff --git a/Cargo.lock b/Cargo.lock index c671c4904..9c09d9dc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,6 +203,29 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytecheck" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c8f430744b23b54ad15161fcbc22d82a29b73eacbe425fea23ec822600bc6f" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "rancor", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523363cbe1df49b68215efdf500b103ac3b0fb4836aed6d15689a076eadb8fff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.82", +] + [[package]] name = "bytemuck" version = "1.19.0" @@ -249,11 +272,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "ceno_host" +version = "0.1.0" +dependencies = [ + "itertools 0.13.0", + "rand", + "rkyv", +] + [[package]] name = "ceno_rt" version = "0.1.0" dependencies = [ "riscv", + "rkyv", ] [[package]] @@ -1083,6 +1116,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "munge" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64142d38c84badf60abf06ff9bd80ad2174306a5b11bd4706535090a30a419df" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb5c1d8184f13f7d0ccbeeca0def2f9a181bce2624302793005f5ca8aa62e5e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.82", +] + [[package]] name = "nix" version = "0.26.4" @@ -1439,6 +1492,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.82", +] + [[package]] name = "quick-xml" version = "0.26.0" @@ -1463,6 +1536,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rancor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" +dependencies = [ + "ptr_meta", +] + [[package]] name = "rand" version = "0.8.5" @@ -1578,6 +1660,15 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rend" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" +dependencies = [ + "bytecheck", +] + [[package]] name = "rgb" version = "0.8.50" @@ -1617,6 +1708,33 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" +[[package]] +name = "rkyv" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11a153aec4a6ab60795f8ebe2923c597b16b05bb1504377451e705ef1a45323" +dependencies = [ + "bytecheck", + "hashbrown 0.15.2", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beb382a4d9f53bd5c0be86b10d8179c3f8a14c30bf774ff77096ed6581e35981" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.82", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1710,6 +1828,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "smallvec" version = "1.13.2" @@ -1913,6 +2037,21 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tracing" version = "0.1.41" diff --git a/Cargo.toml b/Cargo.toml index 593fc5471..9ba75bed7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,14 +2,15 @@ exclude = ["examples"] members = [ "ceno_emul", - "examples-builder", + "ceno_host", "ceno_rt", + "ceno_zkvm", + "examples-builder", "mpcs", "multilinear_extensions", + "poseidon", "sumcheck", "transcript", - "ceno_zkvm", - "poseidon", ] resolver = "2" diff --git a/ceno_host/Cargo.toml b/ceno_host/Cargo.toml new file mode 100644 index 000000000..d72edce86 --- /dev/null +++ b/ceno_host/Cargo.toml @@ -0,0 +1,12 @@ +[package] +edition.workspace = true +license.workspace = true +name = "ceno_host" +version.workspace = true + +[dependencies] +itertools.workspace = true +rkyv = { version = "0.8.9", default-features = false, features = ["alloc", "bytecheck"] } + +[dev-dependencies] +rand.workspace = true diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs new file mode 100644 index 000000000..0fa7293ee --- /dev/null +++ b/ceno_host/src/lib.rs @@ -0,0 +1,250 @@ +// See `make_stdin` and `consume` for the main entry points, and how this would look +// for the host and guest respectively for the user of our library. +// Everything else in here would be hidden. + +use itertools::izip; +use rkyv::{ + Portable, Serialize, + api::high::{HighSerializer, HighValidator}, + bytecheck::CheckBytes, + rancor::Error, + ser::allocator::ArenaHandle, + to_bytes, + util::AlignedVec, +}; + +#[derive(Default)] +pub struct CenoStdin { + pub items: Vec, +} + +pub struct SerialisedCenoStdin(pub AlignedVec); + +impl CenoStdin { + pub fn write_slice(&mut self, bytes: AlignedVec) { + self.items.push(bytes); + } + + pub fn write( + &mut self, + item: &impl for<'a> Serialize, Error>>, + ) -> Result<(), Error> { + let bytes = to_bytes::(item)?; + self.write_slice(bytes); + Ok(()) + } + + pub fn finalise(&self) -> SerialisedCenoStdin { + // TODO: perhaps don't hardcode 16 here. + // It's from rkyv's format, so we can probably take it from there somehow? + // TODO: clean this up. + let initial_offset = (size_of::() * self.items.len()).next_multiple_of(16); + println!("offset: {}", initial_offset); + let offsets: Vec = self + .items + .iter() + .scan(initial_offset, |acc, bytes| { + let output = (*acc + bytes.len()) as u32; + print!("len: {}\t", bytes.len()); + *acc += bytes.len().next_multiple_of(16); + println!("acc: {}", *acc); + Some(output) + }) + .collect(); + let offsets_u8: Vec = offsets.iter().copied().flat_map(u32::to_le_bytes).collect(); + let mut buf: AlignedVec = AlignedVec::new(); + buf.extend_from_slice(&offsets_u8); + println!("buf.len() after offsets: {}", buf.len()); + buf.extend_from_slice(&vec![0; buf.len().next_multiple_of(16) - buf.len()]); + println!("buf.len() after offset padding: {}", buf.len()); + for (offset, item) in izip!(offsets, &self.items) { + buf.extend_from_slice(item); + buf.extend_from_slice(&vec![0; buf.len().next_multiple_of(16) - buf.len()]); + assert_eq!(buf.len(), offset.next_multiple_of(16) as usize); + } + SerialisedCenoStdin(buf) + } +} + +pub struct SerialisedCenoStdinIter<'a> { + buf: &'a SerialisedCenoStdin, + next: usize, +} + +impl<'b> SerialisedCenoStdinIter<'b> { + pub fn read<'a, T>(&'a mut self) -> &'b T + where + T: Portable + for<'c> CheckBytes>, + { + rkyv::access::(self.read_slice()).unwrap() + } + + pub fn read_slice<'a>(&'a mut self) -> &'b [u8] { + self.next().unwrap() + } +} + +impl<'a> Iterator for SerialisedCenoStdinIter<'a> { + type Item = &'a [u8]; + fn next(&mut self) -> Option { + let len = u32::from_le_bytes( + self.buf.0[self.next..][..size_of::()] + .try_into() + .unwrap(), + ) as usize; + self.next += size_of::(); + Some(&self.buf.0[..len]) + } +} + +impl<'a> IntoIterator for &'a SerialisedCenoStdin { + type Item = &'a [u8]; + type IntoIter = SerialisedCenoStdinIter<'a>; + + fn into_iter(self) -> Self::IntoIter { + SerialisedCenoStdinIter { next: 0, buf: self } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::Rng; + use rkyv::{ + Archive, Deserialize, deserialize, + rancor::{Error, Failure}, + to_bytes, + util::AlignedVec, + }; + + #[derive(Archive, Deserialize, Serialize, Debug, PartialEq)] + #[rkyv( + // This will generate a PartialEq impl between our unarchived + // and archived types + compare(PartialEq), + // Derives can be passed through to the generated type: + derive(Debug), + )] + struct Test { + int: u32, + string: String, + option: Option>, + } + + #[derive(Archive, Deserialize, Serialize, Debug, PartialEq)] + #[rkyv( + // This will generate a PartialEq impl between our unarchived + // and archived types + compare(PartialEq), + // Derives can be passed through to the generated type: + derive(Debug), + )] + struct Toast { + stuff: Option>, + } + + /// The equivalent of this function would run in the host. + /// + /// We create three different items, and show that we can read them back in `consume`. + pub fn make_stdin() -> SerialisedCenoStdin { + let mut stdin = CenoStdin::default(); + stdin + .write(&Test { + int: 0xDEAD_BEEF, + string: "hello world".to_string(), + option: Some(vec![1, 2, 3, 4]), + }) + .unwrap(); + stdin.write(&0xaf_u8).unwrap(); + stdin + .write(&Toast { + stuff: Some(vec!["hello scroll".to_string()]), + }) + .unwrap(); + stdin.finalise() + } + + /// The equivalent of this function would run in the guest. + /// + /// `stdin` would be the memory mapped region for private hints. + pub fn consume(stdin: SerialisedCenoStdin) { + println!("\nConsuming..."); + let mut iter: SerialisedCenoStdinIter = stdin.into_iter(); + let test1: &ArchivedTest = iter.read(); + assert_eq!(test1, &Test { + int: 0xDEAD_BEEF, + string: "hello world".to_string(), + option: Some(vec![1, 2, 3, 4]), + }); + let number: &u8 = iter.read(); + assert_eq!(number, &0xaf_u8); + let test2: &ArchivedToast = iter.read(); + assert_eq!(test2, &Toast { + stuff: Some(vec!["hello scroll".to_string()]), + }); + } + + #[test] + fn test_prepare_and_consume_items() { + let stdin = make_stdin(); + consume(stdin); + } + + #[test] + fn test_rkyv_padding() { + let value = Test { + int: 42, + string: "hello world".to_string(), + option: Some(vec![1, 2, 3, 4]), + }; + + // Serializing is as easy as a single function call + let bytes: AlignedVec = to_bytes::(&value).unwrap(); + + { + // Or you can customize your serialization for better performance or control + // over resource usage + use rkyv::{api::high::to_bytes_with_alloc, ser::allocator::Arena}; + + let mut arena = Arena::new(); + let _bytes = to_bytes_with_alloc::<_, Error>(&value, arena.acquire()).unwrap(); + } + // You can use the safe API for fast zero-copy deserialization + let archived = rkyv::access::(&bytes[..]).unwrap(); + assert_eq!(archived, &value); + + // And you can always deserialize back to the original type + let deserialized = deserialize::(archived).unwrap(); + assert_eq!(deserialized, value); + + let mut rng = rand::thread_rng(); + + { + // https://rkyv.org/format.html says: + // This deterministic layout means that you don't need to store the position of + // the root object in most cases. As long as your buffer ends right at the end of + // your root object, you can use `access` with your buffer. + + // Thus left padding should work. We add 1024 bytes of random junk to the left. + + let mut left_padded_bytes = vec![0; 1024]; + rng.fill(&mut left_padded_bytes[..]); + // Then add our original bytes to the end: + left_padded_bytes.extend_from_slice(&bytes); + + // we should be able to access as before: + let archived2 = rkyv::access::(&left_padded_bytes[..]).unwrap(); + assert_eq!(archived2, &value); + } + { + // The same but right padding junk should fail: + let mut right_padded_bytes = bytes.clone(); + let mut junk = vec![0; 1024]; + rng.fill(&mut junk[..]); + right_padded_bytes.extend_from_slice(&junk); + // we should not be able to access as before: + let _ = rkyv::access::(&right_padded_bytes[..]) + .expect_err("This should fail."); + } + } +} diff --git a/ceno_rt/Cargo.toml b/ceno_rt/Cargo.toml index dfdc87ad2..709e80f51 100644 --- a/ceno_rt/Cargo.toml +++ b/ceno_rt/Cargo.toml @@ -11,3 +11,7 @@ version.workspace = true [dependencies] riscv = "0.12" +rkyv = { version = "0.8", default-features = false, features = [ + "alloc", + "bytecheck", +] } diff --git a/ceno_rt/src/allocator.rs b/ceno_rt/src/allocator.rs index c5202f1de..5720ac676 100644 --- a/ceno_rt/src/allocator.rs +++ b/ceno_rt/src/allocator.rs @@ -1,6 +1,8 @@ //! A bump allocator. //! Based on https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html +// Plan: do the same memory trickery as for the allocator. + use core::alloc::{GlobalAlloc, Layout}; struct SimpleAllocator { diff --git a/ceno_rt/src/lib.rs b/ceno_rt/src/lib.rs index 9945057ec..51856a2e1 100644 --- a/ceno_rt/src/lib.rs +++ b/ceno_rt/src/lib.rs @@ -6,6 +6,9 @@ use core::arch::{asm, global_asm}; mod allocator; +mod mmio; +pub use mmio::{read, read_slice}; + mod io; pub use io::info_out; @@ -80,6 +83,8 @@ macro_rules! entry { #[no_mangle] unsafe extern "C" fn _start_rust() -> ! { allocator::init_heap(); + mmio::init_hints(); + { extern "C" { fn bespoke_entrypoint(); diff --git a/ceno_rt/src/mmio.rs b/ceno_rt/src/mmio.rs new file mode 100644 index 000000000..37937d108 --- /dev/null +++ b/ceno_rt/src/mmio.rs @@ -0,0 +1,109 @@ +//! Memory-mapped I/O (MMIO) functions. + +use rkyv::{Portable, api::high::HighValidator, bytecheck::CheckBytes, rancor::Error}; + +use core::slice::from_raw_parts; + +use crate::_hints_start; + +static mut NEXT_HINT_LEN_AT: usize = 0x4000_0000; + +pub unsafe fn init_hints() { + NEXT_HINT_LEN_AT = core::ptr::from_ref::(&_hints_start).cast::() as usize; +} + +// pub const HINTS_START: usize = 0x4000_0000; + +// static mut STDIN: SerialisedCenoStdin = SerialisedCenoStdin(&[]); +// static mut STDIN_ITER: SerialisedCenoStdinIter = unsafe { SerialisedCenoStdinIter { +// next: 0, +// buf: &raw const STDIN, +// }}; + +// // This should only be called once at the start. +// // Similar to how we init the allocator. +// pub fn set_hints_slice() { +// unsafe { +// STDIN = SerialisedCenoStdin(from_raw_parts( +// HINTS.start as *const u8, +// HINTS.end - HINTS.start, +// )) +// }; +// } + +// // static HINTS_SLICE: &[u8] = unsafe { +// // slice::from_raw_parts(HINTS.start as *const u8, HINTS.end - HINTS.start) +// // }; + +// // const HINTS: Range = 0x4000_0000..0x5000_0000; + +// // static HINTS_SLICE: &'static [u8] = +// // unsafe { core::slice::from_raw_parts(HINTS.start as *const u8, HINTS.end - HINTS.start) }; + +// // #[derive(Default)] +// // pub struct CenoStdin { +// // pub items: Vec, +// // } + +// pub struct SerialisedCenoStdin<'a>(&'a [u8]); + +// pub struct SerialisedCenoStdinIter<'a> { +// buf: &'a SerialisedCenoStdin<'a>, +// next: usize, +// } + +// // pub fn read() { + +// // } + +pub fn read_slice<'a>() -> &'a [u8] { + unsafe { + let len: u32 = core::ptr::read(NEXT_HINT_LEN_AT as *const u32); + NEXT_HINT_LEN_AT += 4; + + let start: *const u8 = core::ptr::from_ref::(&crate::_hints_start).cast::(); + &from_raw_parts(start, 1 << 30)[..len as usize] + } +} + +pub fn read<'a, T>() -> &'a T +where + T: Portable + for<'c> CheckBytes>, +{ + rkyv::access::(read_slice()).unwrap() +} + +// impl<'b> SerialisedCenoStdinIter<'b> { +// pub fn read<'a, T>(&'a mut self) -> &'b T +// where +// T: Portable + for<'c> CheckBytes>, +// { +// rkyv::access::(self.read_slice()).unwrap() +// } + +// pub fn read_slice<'a>(&'a mut self) -> &'b [u8] { +// self.next().unwrap() +// } +// } + +// impl<'a> Iterator for SerialisedCenoStdinIter<'a> { +// type Item = &'a [u8]; +// fn next(&mut self) -> Option { +// let len = u32::from_le_bytes( +// self.buf.0[self.next..][..size_of::()] +// .try_into() +// .unwrap(), +// ) as usize; +// self.next += size_of::(); +// Some(&self.buf.0[..len]) +// } +// } + +// impl<'a> IntoIterator for &'a SerialisedCenoStdin<'a> { +// type Item = &'a [u8]; +// type IntoIter = SerialisedCenoStdinIter<'a>; + +// fn into_iter(self) -> Self::IntoIter { +// SerialisedCenoStdinIter { next: 0, buf: self } +// } +// } diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 359355930..a7532992d 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -2,11 +2,35 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "bytecheck" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c8f430744b23b54ad15161fcbc22d82a29b73eacbe425fea23ec822600bc6f" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "rancor", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523363cbe1df49b68215efdf500b103ac3b0fb4836aed6d15689a076eadb8fff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ceno_rt" version = "0.1.0" dependencies = [ "riscv", + "rkyv", ] [[package]] @@ -28,6 +52,32 @@ dependencies = [ "ceno_rt", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "munge" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64142d38c84badf60abf06ff9bd80ad2174306a5b11bd4706535090a30a419df" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb5c1d8184f13f7d0ccbeeca0def2f9a181bce2624302793005f5ca8aa62e5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "paste" version = "1.0.15" @@ -43,6 +93,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.37" @@ -52,6 +122,24 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rancor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" +dependencies = [ + "ptr_meta", +] + +[[package]] +name = "rend" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" +dependencies = [ + "bytecheck", +] + [[package]] name = "riscv" version = "0.12.1" @@ -82,6 +170,39 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" +[[package]] +name = "rkyv" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11a153aec4a6ab60795f8ebe2923c597b16b05bb1504377451e705ef1a45323" +dependencies = [ + "bytecheck", + "hashbrown", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beb382a4d9f53bd5c0be86b10d8179c3f8a14c30bf774ff77096ed6581e35981" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "syn" version = "2.0.82" @@ -93,6 +214,21 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "unicode-ident" version = "1.0.13" From efde5b3514cae333450f01db1cc87a52942dfecc Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 6 Dec 2024 14:18:08 +0800 Subject: [PATCH 03/44] Clean up --- ceno_host/Cargo.toml | 5 ++ ceno_host/src/lib.rs | 194 +------------------------------------------ ceno_rt/memory.x | 1 + 3 files changed, 9 insertions(+), 191 deletions(-) diff --git a/ceno_host/Cargo.toml b/ceno_host/Cargo.toml index d72edce86..e8e54d04e 100644 --- a/ceno_host/Cargo.toml +++ b/ceno_host/Cargo.toml @@ -1,7 +1,12 @@ [package] +categories.workspace = true +description = "Support for the host port of a Ceno application" edition.workspace = true +keywords.workspace = true license.workspace = true name = "ceno_host" +readme.workspace = true +repository.workspace = true version.workspace = true [dependencies] diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index 0fa7293ee..f23a9ce7f 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -4,12 +4,7 @@ use itertools::izip; use rkyv::{ - Portable, Serialize, - api::high::{HighSerializer, HighValidator}, - bytecheck::CheckBytes, - rancor::Error, - ser::allocator::ArenaHandle, - to_bytes, + Serialize, api::high::HighSerializer, rancor::Error, ser::allocator::ArenaHandle, to_bytes, util::AlignedVec, }; @@ -34,7 +29,7 @@ impl CenoStdin { Ok(()) } - pub fn finalise(&self) -> SerialisedCenoStdin { + pub fn finalise(&self) -> AlignedVec { // TODO: perhaps don't hardcode 16 here. // It's from rkyv's format, so we can probably take it from there somehow? // TODO: clean this up. @@ -62,189 +57,6 @@ impl CenoStdin { buf.extend_from_slice(&vec![0; buf.len().next_multiple_of(16) - buf.len()]); assert_eq!(buf.len(), offset.next_multiple_of(16) as usize); } - SerialisedCenoStdin(buf) - } -} - -pub struct SerialisedCenoStdinIter<'a> { - buf: &'a SerialisedCenoStdin, - next: usize, -} - -impl<'b> SerialisedCenoStdinIter<'b> { - pub fn read<'a, T>(&'a mut self) -> &'b T - where - T: Portable + for<'c> CheckBytes>, - { - rkyv::access::(self.read_slice()).unwrap() - } - - pub fn read_slice<'a>(&'a mut self) -> &'b [u8] { - self.next().unwrap() - } -} - -impl<'a> Iterator for SerialisedCenoStdinIter<'a> { - type Item = &'a [u8]; - fn next(&mut self) -> Option { - let len = u32::from_le_bytes( - self.buf.0[self.next..][..size_of::()] - .try_into() - .unwrap(), - ) as usize; - self.next += size_of::(); - Some(&self.buf.0[..len]) - } -} - -impl<'a> IntoIterator for &'a SerialisedCenoStdin { - type Item = &'a [u8]; - type IntoIter = SerialisedCenoStdinIter<'a>; - - fn into_iter(self) -> Self::IntoIter { - SerialisedCenoStdinIter { next: 0, buf: self } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use rand::Rng; - use rkyv::{ - Archive, Deserialize, deserialize, - rancor::{Error, Failure}, - to_bytes, - util::AlignedVec, - }; - - #[derive(Archive, Deserialize, Serialize, Debug, PartialEq)] - #[rkyv( - // This will generate a PartialEq impl between our unarchived - // and archived types - compare(PartialEq), - // Derives can be passed through to the generated type: - derive(Debug), - )] - struct Test { - int: u32, - string: String, - option: Option>, - } - - #[derive(Archive, Deserialize, Serialize, Debug, PartialEq)] - #[rkyv( - // This will generate a PartialEq impl between our unarchived - // and archived types - compare(PartialEq), - // Derives can be passed through to the generated type: - derive(Debug), - )] - struct Toast { - stuff: Option>, - } - - /// The equivalent of this function would run in the host. - /// - /// We create three different items, and show that we can read them back in `consume`. - pub fn make_stdin() -> SerialisedCenoStdin { - let mut stdin = CenoStdin::default(); - stdin - .write(&Test { - int: 0xDEAD_BEEF, - string: "hello world".to_string(), - option: Some(vec![1, 2, 3, 4]), - }) - .unwrap(); - stdin.write(&0xaf_u8).unwrap(); - stdin - .write(&Toast { - stuff: Some(vec!["hello scroll".to_string()]), - }) - .unwrap(); - stdin.finalise() - } - - /// The equivalent of this function would run in the guest. - /// - /// `stdin` would be the memory mapped region for private hints. - pub fn consume(stdin: SerialisedCenoStdin) { - println!("\nConsuming..."); - let mut iter: SerialisedCenoStdinIter = stdin.into_iter(); - let test1: &ArchivedTest = iter.read(); - assert_eq!(test1, &Test { - int: 0xDEAD_BEEF, - string: "hello world".to_string(), - option: Some(vec![1, 2, 3, 4]), - }); - let number: &u8 = iter.read(); - assert_eq!(number, &0xaf_u8); - let test2: &ArchivedToast = iter.read(); - assert_eq!(test2, &Toast { - stuff: Some(vec!["hello scroll".to_string()]), - }); - } - - #[test] - fn test_prepare_and_consume_items() { - let stdin = make_stdin(); - consume(stdin); - } - - #[test] - fn test_rkyv_padding() { - let value = Test { - int: 42, - string: "hello world".to_string(), - option: Some(vec![1, 2, 3, 4]), - }; - - // Serializing is as easy as a single function call - let bytes: AlignedVec = to_bytes::(&value).unwrap(); - - { - // Or you can customize your serialization for better performance or control - // over resource usage - use rkyv::{api::high::to_bytes_with_alloc, ser::allocator::Arena}; - - let mut arena = Arena::new(); - let _bytes = to_bytes_with_alloc::<_, Error>(&value, arena.acquire()).unwrap(); - } - // You can use the safe API for fast zero-copy deserialization - let archived = rkyv::access::(&bytes[..]).unwrap(); - assert_eq!(archived, &value); - - // And you can always deserialize back to the original type - let deserialized = deserialize::(archived).unwrap(); - assert_eq!(deserialized, value); - - let mut rng = rand::thread_rng(); - - { - // https://rkyv.org/format.html says: - // This deterministic layout means that you don't need to store the position of - // the root object in most cases. As long as your buffer ends right at the end of - // your root object, you can use `access` with your buffer. - - // Thus left padding should work. We add 1024 bytes of random junk to the left. - - let mut left_padded_bytes = vec![0; 1024]; - rng.fill(&mut left_padded_bytes[..]); - // Then add our original bytes to the end: - left_padded_bytes.extend_from_slice(&bytes); - - // we should be able to access as before: - let archived2 = rkyv::access::(&left_padded_bytes[..]).unwrap(); - assert_eq!(archived2, &value); - } - { - // The same but right padding junk should fail: - let mut right_padded_bytes = bytes.clone(); - let mut junk = vec![0; 1024]; - rng.fill(&mut junk[..]); - right_padded_bytes.extend_from_slice(&junk); - // we should not be able to access as before: - let _ = rkyv::access::(&right_padded_bytes[..]) - .expect_err("This should fail."); - } + buf } } diff --git a/ceno_rt/memory.x b/ceno_rt/memory.x index 7c2a2538b..0baf12fcd 100644 --- a/ceno_rt/memory.x +++ b/ceno_rt/memory.x @@ -11,4 +11,5 @@ REGION_ALIAS("REGION_DATA", RAM); REGION_ALIAS("REGION_BSS", RAM); REGION_ALIAS("REGION_HEAP", RAM); REGION_ALIAS("REGION_STACK", RAM); + REGION_ALIAS("REGION_HINTS", HINTS); From d7949a65027f93205df86cc46d64a0352fa132ae Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 6 Dec 2024 14:56:18 +0800 Subject: [PATCH 04/44] Snapshot --- Cargo.lock | 2 ++ Cargo.toml | 1 + ceno_emul/Cargo.toml | 2 +- ceno_host/Cargo.toml | 2 ++ ceno_host/src/lib.rs | 71 +++++++++++++++++++++++++++++++++++++++----- 5 files changed, 70 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c09d9dc1..5049c3f62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -276,6 +276,8 @@ dependencies = [ name = "ceno_host" version = "0.1.0" dependencies = [ + "anyhow", + "ceno_emul", "itertools 0.13.0", "rand", "rkyv", diff --git a/Cargo.toml b/Cargo.toml index 9ba75bed7..86a00b462 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ repository = "https://github.com/scroll-tech/ceno" version = "0.1.0" [workspace.dependencies] +anyhow = { version = "1.0", default-features = false } ark-std = "0.4" cfg-if = "1.0" criterion = { version = "0.5", features = ["html_reports"] } diff --git a/ceno_emul/Cargo.toml b/ceno_emul/Cargo.toml index 38f0a8bfd..127dc9f4c 100644 --- a/ceno_emul/Cargo.toml +++ b/ceno_emul/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true version.workspace = true [dependencies] -anyhow = { version = "1.0", default-features = false } +anyhow.workspace = true elf = "0.7" itertools.workspace = true num-derive.workspace = true diff --git a/ceno_host/Cargo.toml b/ceno_host/Cargo.toml index e8e54d04e..eb3395aa4 100644 --- a/ceno_host/Cargo.toml +++ b/ceno_host/Cargo.toml @@ -10,8 +10,10 @@ repository.workspace = true version.workspace = true [dependencies] +anyhow.workspace = true itertools.workspace = true rkyv = { version = "0.8.9", default-features = false, features = ["alloc", "bytecheck"] } +ceno_emul = { path = "../ceno_emul" } [dev-dependencies] rand.workspace = true diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index f23a9ce7f..2a64bd0e8 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -2,6 +2,10 @@ // for the host and guest respectively for the user of our library. // Everything else in here would be hidden. +use std::iter::zip; + +use anyhow::Result; +use ceno_emul::{ByteAddr, EmuContext, IterAddresses, Platform, VMState}; use itertools::izip; use rkyv::{ Serialize, api::high::HighSerializer, rancor::Error, ser::allocator::ArenaHandle, to_bytes, @@ -29,34 +33,87 @@ impl CenoStdin { Ok(()) } - pub fn finalise(&self) -> AlignedVec { + pub fn finalise(&self) -> Vec { // TODO: perhaps don't hardcode 16 here. // It's from rkyv's format, so we can probably take it from there somehow? // TODO: clean this up. let initial_offset = (size_of::() * self.items.len()).next_multiple_of(16); - println!("offset: {}", initial_offset); + // println!("offset: {}", initial_offset); let offsets: Vec = self .items .iter() .scan(initial_offset, |acc, bytes| { let output = (*acc + bytes.len()) as u32; - print!("len: {}\t", bytes.len()); + // print!("len: {}\t", bytes.len()); *acc += bytes.len().next_multiple_of(16); - println!("acc: {}", *acc); + // println!("acc: {}", *acc); Some(output) }) .collect(); let offsets_u8: Vec = offsets.iter().copied().flat_map(u32::to_le_bytes).collect(); let mut buf: AlignedVec = AlignedVec::new(); buf.extend_from_slice(&offsets_u8); - println!("buf.len() after offsets: {}", buf.len()); + // println!("buf.len() after offsets: {}", buf.len()); buf.extend_from_slice(&vec![0; buf.len().next_multiple_of(16) - buf.len()]); - println!("buf.len() after offset padding: {}", buf.len()); + // println!("buf.len() after offset padding: {}", buf.len()); for (offset, item) in izip!(offsets, &self.items) { buf.extend_from_slice(item); buf.extend_from_slice(&vec![0; buf.len().next_multiple_of(16) - buf.len()]); assert_eq!(buf.len(), offset.next_multiple_of(16) as usize); } - buf + let (prefix, hints, postfix): (_, &[u32], _) = unsafe { buf.align_to() }; + assert_eq!(prefix, &[]); + assert_eq!(postfix, &[]); + hints.to_vec() + } +} + +// TODO: clean up, don't copy and paste. +const WORD_SIZE: usize = 4; +const INFO_OUT_ADDR: u32 = 0xC000_0000; + +fn read_all_messages(state: &VMState) -> Vec { + let mut all_messages = Vec::new(); + let mut word_offset = 0; + loop { + let out = read_message(state, word_offset); + if out.is_empty() { + break; + } + word_offset += out.len().div_ceil(WORD_SIZE) as u32 + 1; + all_messages.push(out); + } + all_messages +} + +fn read_message(state: &VMState, word_offset: u32) -> String { + let out_addr = ByteAddr(INFO_OUT_ADDR).waddr() + word_offset; + let byte_len = state.peek_memory(out_addr); + let word_len_up = byte_len.div_ceil(4); + + let mut info_out = Vec::with_capacity(WORD_SIZE * word_len_up as usize); + for i in 1..1 + word_len_up { + let value = state.peek_memory(out_addr + i); + info_out.extend_from_slice(&value.to_le_bytes()); + } + info_out.truncate(byte_len as usize); + String::from_utf8_lossy(&info_out).to_string() +} + +// TODO(Matthias): also return exit code (if any) +pub fn run(platform: Platform, elf: &[u8], hints: &CenoStdin) -> Vec { + let hints: Vec = hints.finalise(); + + let mut state = VMState::new_from_elf(platform.clone(), elf).expect("Failed to load ELF"); + + for (addr, value) in zip(platform.hints.iter_addresses(), hints) { + state.init_memory(addr.into(), value); } + + let steps = state + .iter_until_halt() + .collect::>>() + .expect("Failed to run the program"); + eprintln!("Emulator ran for {} steps.", steps.len()); + read_all_messages(&state) } From e002be2ca7c6f87f90824d847402373c27784d64 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 6 Dec 2024 15:06:27 +0800 Subject: [PATCH 05/44] Clean up --- ceno_host/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index 2a64bd0e8..f9c74c4f8 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -1,7 +1,3 @@ -// See `make_stdin` and `consume` for the main entry points, and how this would look -// for the host and guest respectively for the user of our library. -// Everything else in here would be hidden. - use std::iter::zip; use anyhow::Result; From 8a4906ff459bd47873e4538c5746f7dd8ca4082d Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 6 Dec 2024 15:06:52 +0800 Subject: [PATCH 06/44] Clean up --- ceno_host/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index f9c74c4f8..cd82dc275 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -13,8 +13,6 @@ pub struct CenoStdin { pub items: Vec, } -pub struct SerialisedCenoStdin(pub AlignedVec); - impl CenoStdin { pub fn write_slice(&mut self, bytes: AlignedVec) { self.items.push(bytes); From b789f432f2a036b9b96ee128529542708708b5da Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 6 Dec 2024 15:07:43 +0800 Subject: [PATCH 07/44] Clean up --- ceno_host/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index cd82dc275..95d265d75 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -22,9 +22,7 @@ impl CenoStdin { &mut self, item: &impl for<'a> Serialize, Error>>, ) -> Result<(), Error> { - let bytes = to_bytes::(item)?; - self.write_slice(bytes); - Ok(()) + to_bytes::(item).map(|bytes| self.write_slice(bytes)) } pub fn finalise(&self) -> Vec { From d0af9d85822a1602575e624187c1bda52e2e82e5 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 6 Dec 2024 15:26:25 +0800 Subject: [PATCH 08/44] Clean up --- ceno_rt/src/allocator.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ceno_rt/src/allocator.rs b/ceno_rt/src/allocator.rs index 5720ac676..c5202f1de 100644 --- a/ceno_rt/src/allocator.rs +++ b/ceno_rt/src/allocator.rs @@ -1,8 +1,6 @@ //! A bump allocator. //! Based on https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html -// Plan: do the same memory trickery as for the allocator. - use core::alloc::{GlobalAlloc, Layout}; struct SimpleAllocator { From 83333317f9396dd1fbc4edcf3c8afdbeb1f39dc4 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 6 Dec 2024 15:27:11 +0800 Subject: [PATCH 09/44] Remove commented out code --- ceno_rt/src/mmio.rs | 79 --------------------------------------------- 1 file changed, 79 deletions(-) diff --git a/ceno_rt/src/mmio.rs b/ceno_rt/src/mmio.rs index 37937d108..052fabf63 100644 --- a/ceno_rt/src/mmio.rs +++ b/ceno_rt/src/mmio.rs @@ -12,50 +12,6 @@ pub unsafe fn init_hints() { NEXT_HINT_LEN_AT = core::ptr::from_ref::(&_hints_start).cast::() as usize; } -// pub const HINTS_START: usize = 0x4000_0000; - -// static mut STDIN: SerialisedCenoStdin = SerialisedCenoStdin(&[]); -// static mut STDIN_ITER: SerialisedCenoStdinIter = unsafe { SerialisedCenoStdinIter { -// next: 0, -// buf: &raw const STDIN, -// }}; - -// // This should only be called once at the start. -// // Similar to how we init the allocator. -// pub fn set_hints_slice() { -// unsafe { -// STDIN = SerialisedCenoStdin(from_raw_parts( -// HINTS.start as *const u8, -// HINTS.end - HINTS.start, -// )) -// }; -// } - -// // static HINTS_SLICE: &[u8] = unsafe { -// // slice::from_raw_parts(HINTS.start as *const u8, HINTS.end - HINTS.start) -// // }; - -// // const HINTS: Range = 0x4000_0000..0x5000_0000; - -// // static HINTS_SLICE: &'static [u8] = -// // unsafe { core::slice::from_raw_parts(HINTS.start as *const u8, HINTS.end - HINTS.start) }; - -// // #[derive(Default)] -// // pub struct CenoStdin { -// // pub items: Vec, -// // } - -// pub struct SerialisedCenoStdin<'a>(&'a [u8]); - -// pub struct SerialisedCenoStdinIter<'a> { -// buf: &'a SerialisedCenoStdin<'a>, -// next: usize, -// } - -// // pub fn read() { - -// // } - pub fn read_slice<'a>() -> &'a [u8] { unsafe { let len: u32 = core::ptr::read(NEXT_HINT_LEN_AT as *const u32); @@ -72,38 +28,3 @@ where { rkyv::access::(read_slice()).unwrap() } - -// impl<'b> SerialisedCenoStdinIter<'b> { -// pub fn read<'a, T>(&'a mut self) -> &'b T -// where -// T: Portable + for<'c> CheckBytes>, -// { -// rkyv::access::(self.read_slice()).unwrap() -// } - -// pub fn read_slice<'a>(&'a mut self) -> &'b [u8] { -// self.next().unwrap() -// } -// } - -// impl<'a> Iterator for SerialisedCenoStdinIter<'a> { -// type Item = &'a [u8]; -// fn next(&mut self) -> Option { -// let len = u32::from_le_bytes( -// self.buf.0[self.next..][..size_of::()] -// .try_into() -// .unwrap(), -// ) as usize; -// self.next += size_of::(); -// Some(&self.buf.0[..len]) -// } -// } - -// impl<'a> IntoIterator for &'a SerialisedCenoStdin<'a> { -// type Item = &'a [u8]; -// type IntoIter = SerialisedCenoStdinIter<'a>; - -// fn into_iter(self) -> Self::IntoIter { -// SerialisedCenoStdinIter { next: 0, buf: self } -// } -// } From 8597909a0edf8509d54ebfc546c5a8b7e1ab391d Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 6 Dec 2024 15:29:57 +0800 Subject: [PATCH 10/44] Clarify comment --- ceno_host/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index 95d265d75..c64bce07d 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -60,7 +60,9 @@ impl CenoStdin { } } -// TODO: clean up, don't copy and paste. +// TODO(Matthias): much of this is copied from `test_elf.rs` in Ceno. These are generally useful +// functions, so we should make them available for both crates, instead of copy-and-pasting here. + const WORD_SIZE: usize = 4; const INFO_OUT_ADDR: u32 = 0xC000_0000; From 1b14291d51265d81b7d698d3b4d5c8ccef02371a Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 6 Dec 2024 18:38:19 +0800 Subject: [PATCH 11/44] taplo fmt --- ceno_host/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ceno_host/Cargo.toml b/ceno_host/Cargo.toml index eb3395aa4..e8907cef6 100644 --- a/ceno_host/Cargo.toml +++ b/ceno_host/Cargo.toml @@ -11,9 +11,9 @@ version.workspace = true [dependencies] anyhow.workspace = true +ceno_emul = { path = "../ceno_emul" } itertools.workspace = true rkyv = { version = "0.8.9", default-features = false, features = ["alloc", "bytecheck"] } -ceno_emul = { path = "../ceno_emul" } [dev-dependencies] rand.workspace = true From 9280a9fc690162ba3fbed9141a60fbab08a0bbc6 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 16:00:23 +0800 Subject: [PATCH 12/44] Clean up --- Cargo.lock | 8 ++++---- ceno_host/src/lib.rs | 32 +++++++++++++++++++------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6bfa8af1e..960028af5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -217,7 +217,7 @@ checksum = "523363cbe1df49b68215efdf500b103ac3b0fb4836aed6d15689a076eadb8fff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.90", ] [[package]] @@ -1129,7 +1129,7 @@ checksum = "1bb5c1d8184f13f7d0ccbeeca0def2f9a181bce2624302793005f5ca8aa62e5e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.90", ] [[package]] @@ -1505,7 +1505,7 @@ checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.90", ] [[package]] @@ -1728,7 +1728,7 @@ checksum = "beb382a4d9f53bd5c0be86b10d8179c3f8a14c30bf774ff77096ed6581e35981" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.90", ] [[package]] diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index c64bce07d..ac90f7d1d 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -8,6 +8,14 @@ use rkyv::{ util::AlignedVec, }; +// We want to get access to the default value of `AlignedVec::ALIGNMENT`, and using it directly like this +// pub const RKVY_ALIGNMENT: usize = rkyv::util::AlignedVec::ALIGNMENT; +// doesn't work: +pub const RKYV_ALIGNMENT: usize = { + type AlignedVec = rkyv::util::AlignedVec; + AlignedVec::ALIGNMENT +}; + #[derive(Default)] pub struct CenoStdin { pub items: Vec, @@ -26,32 +34,30 @@ impl CenoStdin { } pub fn finalise(&self) -> Vec { - // TODO: perhaps don't hardcode 16 here. - // It's from rkyv's format, so we can probably take it from there somehow? - // TODO: clean this up. - let initial_offset = (size_of::() * self.items.len()).next_multiple_of(16); - // println!("offset: {}", initial_offset); + let initial_offset = (size_of::() * self.items.len()).next_multiple_of(RKYV_ALIGNMENT); let offsets: Vec = self .items .iter() .scan(initial_offset, |acc, bytes| { let output = (*acc + bytes.len()) as u32; - // print!("len: {}\t", bytes.len()); - *acc += bytes.len().next_multiple_of(16); - // println!("acc: {}", *acc); + *acc += bytes.len().next_multiple_of(RKYV_ALIGNMENT); Some(output) }) .collect(); let offsets_u8: Vec = offsets.iter().copied().flat_map(u32::to_le_bytes).collect(); let mut buf: AlignedVec = AlignedVec::new(); buf.extend_from_slice(&offsets_u8); - // println!("buf.len() after offsets: {}", buf.len()); - buf.extend_from_slice(&vec![0; buf.len().next_multiple_of(16) - buf.len()]); - // println!("buf.len() after offset padding: {}", buf.len()); + buf.extend_from_slice(&vec![ + 0; + buf.len().next_multiple_of(RKYV_ALIGNMENT) - buf.len() + ]); for (offset, item) in izip!(offsets, &self.items) { buf.extend_from_slice(item); - buf.extend_from_slice(&vec![0; buf.len().next_multiple_of(16) - buf.len()]); - assert_eq!(buf.len(), offset.next_multiple_of(16) as usize); + buf.extend_from_slice(&vec![ + 0; + buf.len().next_multiple_of(RKYV_ALIGNMENT) - buf.len() + ]); + assert_eq!(buf.len(), offset.next_multiple_of(RKYV_ALIGNMENT) as usize); } let (prefix, hints, postfix): (_, &[u32], _) = unsafe { buf.align_to() }; assert_eq!(prefix, &[]); From 1ac5c7c4a6040f35cb431ee210ca1b63067712b3 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 16:04:28 +0800 Subject: [PATCH 13/44] Fix --- ceno_host/src/lib.rs | 5 ++++- ceno_rt/src/mmio.rs | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index ac90f7d1d..134225015 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -57,7 +57,10 @@ impl CenoStdin { 0; buf.len().next_multiple_of(RKYV_ALIGNMENT) - buf.len() ]); - assert_eq!(buf.len(), offset.next_multiple_of(RKYV_ALIGNMENT) as usize); + assert_eq!( + buf.len(), + (offset as usize).next_multiple_of(RKYV_ALIGNMENT) + ); } let (prefix, hints, postfix): (_, &[u32], _) = unsafe { buf.align_to() }; assert_eq!(prefix, &[]); diff --git a/ceno_rt/src/mmio.rs b/ceno_rt/src/mmio.rs index 052fabf63..49598f780 100644 --- a/ceno_rt/src/mmio.rs +++ b/ceno_rt/src/mmio.rs @@ -1,6 +1,6 @@ //! Memory-mapped I/O (MMIO) functions. -use rkyv::{Portable, api::high::HighValidator, bytecheck::CheckBytes, rancor::Error}; +use rkyv::{Portable, api::high::HighValidator, bytecheck::CheckBytes, rancor::Failure}; use core::slice::from_raw_parts; @@ -24,7 +24,7 @@ pub fn read_slice<'a>() -> &'a [u8] { pub fn read<'a, T>() -> &'a T where - T: Portable + for<'c> CheckBytes>, + T: Portable + for<'c> CheckBytes>, { - rkyv::access::(read_slice()).unwrap() + rkyv::access::(read_slice()).unwrap() } From c00a5cbb6a3b4584acc24c90420b90d6f2b33455 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 16:05:57 +0800 Subject: [PATCH 14/44] Expect --- ceno_rt/src/mmio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ceno_rt/src/mmio.rs b/ceno_rt/src/mmio.rs index 49598f780..aaaca16d2 100644 --- a/ceno_rt/src/mmio.rs +++ b/ceno_rt/src/mmio.rs @@ -26,5 +26,5 @@ pub fn read<'a, T>() -> &'a T where T: Portable + for<'c> CheckBytes>, { - rkyv::access::(read_slice()).unwrap() + rkyv::access::(read_slice()).expect("Deserialised access failed.") } From 2b2a48c672076ccc034222cbc788c8b647620fdf Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 16:33:34 +0800 Subject: [PATCH 15/44] Simpler --- ceno_rt/src/allocator.rs | 21 ++++++++++----------- ceno_rt/src/lib.rs | 15 +++------------ ceno_rt/src/mmio.rs | 18 +++++++++--------- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/ceno_rt/src/allocator.rs b/ceno_rt/src/allocator.rs index c5202f1de..da6fc5b53 100644 --- a/ceno_rt/src/allocator.rs +++ b/ceno_rt/src/allocator.rs @@ -4,7 +4,7 @@ use core::alloc::{GlobalAlloc, Layout}; struct SimpleAllocator { - next_alloc: usize, + next_alloc: *mut u8, } unsafe impl GlobalAlloc for SimpleAllocator { @@ -14,16 +14,14 @@ unsafe impl GlobalAlloc for SimpleAllocator { let align = layout.align(); // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2. - // So we can safely use subtraction and a mask to ensure alignment without worrying about UB. - let offset = heap_pos & (align - 1); - if offset != 0 { - heap_pos = heap_pos.strict_add(align.strict_sub(offset)); - } + core::hint::assert_unchecked(align.is_power_of_two()); + core::hint::assert_unchecked(align != 0); + heap_pos = heap_pos.map_addr(|a| a.next_multiple_of(align)); - let ptr = heap_pos as *mut u8; + let ptr = heap_pos; // Panic on overflow. We don't want to wrap around, and overwrite stack etc. // (We could also return a null pointer, but only malicious programs would ever hit this.) - heap_pos = heap_pos.strict_add(layout.size()); + heap_pos = heap_pos.add(layout.size()); HEAP.next_alloc = heap_pos; ptr @@ -41,9 +39,10 @@ unsafe impl GlobalAlloc for SimpleAllocator { // We initialize `next_alloc` to 0xFFFF_FFFF to indicate that the heap has not been initialized. // The value is chosen to make any premature allocation fail. static mut HEAP: SimpleAllocator = SimpleAllocator { - next_alloc: 0xFFFF_FFFF, + next_alloc: &raw mut _sheap, }; -pub unsafe fn init_heap() { - HEAP.next_alloc = core::ptr::from_ref::(&crate::_sheap).cast::() as usize; +extern "C" { + // The address of this variable is the start of the heap (growing upwards). + static mut _sheap: u8; } diff --git a/ceno_rt/src/lib.rs b/ceno_rt/src/lib.rs index 51856a2e1..c27f02145 100644 --- a/ceno_rt/src/lib.rs +++ b/ceno_rt/src/lib.rs @@ -82,23 +82,14 @@ macro_rules! entry { /// _start_rust is called by the assembly entry point and it calls the Rust main(). #[no_mangle] unsafe extern "C" fn _start_rust() -> ! { - allocator::init_heap(); - mmio::init_hints(); - - { - extern "C" { - fn bespoke_entrypoint(); - } - bespoke_entrypoint(); + extern "C" { + fn bespoke_entrypoint(); } + bespoke_entrypoint(); halt(0) } extern "C" { // The address of this variable is the start of the stack (growing downwards). static _stack_start: u8; - // The address of this variable is the start of the heap (growing upwards). - static _sheap: u8; - // The address of this variable is the start of the hints ROM. - static _hints_start: u8; } diff --git a/ceno_rt/src/mmio.rs b/ceno_rt/src/mmio.rs index aaaca16d2..769cd820b 100644 --- a/ceno_rt/src/mmio.rs +++ b/ceno_rt/src/mmio.rs @@ -4,21 +4,21 @@ use rkyv::{Portable, api::high::HighValidator, bytecheck::CheckBytes, rancor::Fa use core::slice::from_raw_parts; -use crate::_hints_start; - -static mut NEXT_HINT_LEN_AT: usize = 0x4000_0000; - -pub unsafe fn init_hints() { - NEXT_HINT_LEN_AT = core::ptr::from_ref::(&_hints_start).cast::() as usize; +extern "C" { + // The address of this variable is the start of the hints ROM. + static _hints_start: u8; } +static mut NEXT_HINT_LEN_AT: *const u8 = unsafe { &_hints_start }; +// next_alloc: &raw crate::_hints_start; +// unsafe { core::ptr::from_ref::(&_hints_start).cast::() }; + pub fn read_slice<'a>() -> &'a [u8] { unsafe { let len: u32 = core::ptr::read(NEXT_HINT_LEN_AT as *const u32); - NEXT_HINT_LEN_AT += 4; + NEXT_HINT_LEN_AT = NEXT_HINT_LEN_AT.wrapping_add(4); - let start: *const u8 = core::ptr::from_ref::(&crate::_hints_start).cast::(); - &from_raw_parts(start, 1 << 30)[..len as usize] + &from_raw_parts(&_hints_start, 1 << 30)[..len as usize] } } From 1ba96925b0516006a28774fda916ef529081ce81 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 16:42:38 +0800 Subject: [PATCH 16/44] Simpler --- ceno_rt/src/allocator.rs | 24 +++++++++++------------- ceno_rt/src/mmio.rs | 4 +--- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/ceno_rt/src/allocator.rs b/ceno_rt/src/allocator.rs index da6fc5b53..fc7064822 100644 --- a/ceno_rt/src/allocator.rs +++ b/ceno_rt/src/allocator.rs @@ -7,6 +7,16 @@ struct SimpleAllocator { next_alloc: *mut u8, } +extern "C" { + // The address of this variable is the start of the heap (growing upwards). + static mut _sheap: u8; +} + +#[global_allocator] +static mut HEAP: SimpleAllocator = SimpleAllocator { + next_alloc: &raw mut _sheap, +}; + unsafe impl GlobalAlloc for SimpleAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { // SAFETY: Single threaded, so nothing else can touch this while we're working. @@ -16,7 +26,7 @@ unsafe impl GlobalAlloc for SimpleAllocator { // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2. core::hint::assert_unchecked(align.is_power_of_two()); core::hint::assert_unchecked(align != 0); - heap_pos = heap_pos.map_addr(|a| a.next_multiple_of(align)); + heap_pos = heap_pos.add(heap_pos.align_offset(align)); let ptr = heap_pos; // Panic on overflow. We don't want to wrap around, and overwrite stack etc. @@ -34,15 +44,3 @@ unsafe impl GlobalAlloc for SimpleAllocator { /// Never deallocate. unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} } - -#[global_allocator] -// We initialize `next_alloc` to 0xFFFF_FFFF to indicate that the heap has not been initialized. -// The value is chosen to make any premature allocation fail. -static mut HEAP: SimpleAllocator = SimpleAllocator { - next_alloc: &raw mut _sheap, -}; - -extern "C" { - // The address of this variable is the start of the heap (growing upwards). - static mut _sheap: u8; -} diff --git a/ceno_rt/src/mmio.rs b/ceno_rt/src/mmio.rs index 769cd820b..af38d6d35 100644 --- a/ceno_rt/src/mmio.rs +++ b/ceno_rt/src/mmio.rs @@ -9,9 +9,7 @@ extern "C" { static _hints_start: u8; } -static mut NEXT_HINT_LEN_AT: *const u8 = unsafe { &_hints_start }; -// next_alloc: &raw crate::_hints_start; -// unsafe { core::ptr::from_ref::(&_hints_start).cast::() }; +static mut NEXT_HINT_LEN_AT: *const u8 = &raw const _hints_start; pub fn read_slice<'a>() -> &'a [u8] { unsafe { From 35bacc32e0a18c80b7930ac0aefdd2f3c288c968 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 16:49:44 +0800 Subject: [PATCH 17/44] Explain --- ceno_rt/src/allocator.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ceno_rt/src/allocator.rs b/ceno_rt/src/allocator.rs index fc7064822..5d26d7188 100644 --- a/ceno_rt/src/allocator.rs +++ b/ceno_rt/src/allocator.rs @@ -8,7 +8,9 @@ struct SimpleAllocator { } extern "C" { - // The address of this variable is the start of the heap (growing upwards). + /// The address of this variable is the start of the heap (growing upwards). + /// + /// It is defined in the linker script. static mut _sheap: u8; } From c27881fa1a3c18fe0dc605df499ab573aceebb2e Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 16:51:36 +0800 Subject: [PATCH 18/44] Explain --- ceno_rt/src/allocator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ceno_rt/src/allocator.rs b/ceno_rt/src/allocator.rs index 5d26d7188..232bbc313 100644 --- a/ceno_rt/src/allocator.rs +++ b/ceno_rt/src/allocator.rs @@ -31,7 +31,7 @@ unsafe impl GlobalAlloc for SimpleAllocator { heap_pos = heap_pos.add(heap_pos.align_offset(align)); let ptr = heap_pos; - // Panic on overflow. We don't want to wrap around, and overwrite stack etc. + // We don't want to wrap around, and overwrite stack etc. // (We could also return a null pointer, but only malicious programs would ever hit this.) heap_pos = heap_pos.add(layout.size()); From ef10c0ad86ef0029fc58db13c518068ff7f6f84f Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 16:52:10 +0800 Subject: [PATCH 19/44] Minimise diff --- ceno_rt/src/allocator.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ceno_rt/src/allocator.rs b/ceno_rt/src/allocator.rs index 232bbc313..91c697b7f 100644 --- a/ceno_rt/src/allocator.rs +++ b/ceno_rt/src/allocator.rs @@ -7,18 +7,6 @@ struct SimpleAllocator { next_alloc: *mut u8, } -extern "C" { - /// The address of this variable is the start of the heap (growing upwards). - /// - /// It is defined in the linker script. - static mut _sheap: u8; -} - -#[global_allocator] -static mut HEAP: SimpleAllocator = SimpleAllocator { - next_alloc: &raw mut _sheap, -}; - unsafe impl GlobalAlloc for SimpleAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { // SAFETY: Single threaded, so nothing else can touch this while we're working. @@ -46,3 +34,15 @@ unsafe impl GlobalAlloc for SimpleAllocator { /// Never deallocate. unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} } + +extern "C" { + /// The address of this variable is the start of the heap (growing upwards). + /// + /// It is defined in the linker script. + static mut _sheap: u8; +} + +#[global_allocator] +static mut HEAP: SimpleAllocator = SimpleAllocator { + next_alloc: &raw mut _sheap, +}; From fecac1afc0498ebb3cdc0ea3e98135a6a330307f Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 16:55:54 +0800 Subject: [PATCH 20/44] Minimise diff --- ceno_rt/src/allocator.rs | 33 +++++++++++++++++---------------- ceno_rt/src/lib.rs | 11 ++++++++--- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/ceno_rt/src/allocator.rs b/ceno_rt/src/allocator.rs index 91c697b7f..c5202f1de 100644 --- a/ceno_rt/src/allocator.rs +++ b/ceno_rt/src/allocator.rs @@ -4,7 +4,7 @@ use core::alloc::{GlobalAlloc, Layout}; struct SimpleAllocator { - next_alloc: *mut u8, + next_alloc: usize, } unsafe impl GlobalAlloc for SimpleAllocator { @@ -14,14 +14,16 @@ unsafe impl GlobalAlloc for SimpleAllocator { let align = layout.align(); // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2. - core::hint::assert_unchecked(align.is_power_of_two()); - core::hint::assert_unchecked(align != 0); - heap_pos = heap_pos.add(heap_pos.align_offset(align)); - - let ptr = heap_pos; - // We don't want to wrap around, and overwrite stack etc. + // So we can safely use subtraction and a mask to ensure alignment without worrying about UB. + let offset = heap_pos & (align - 1); + if offset != 0 { + heap_pos = heap_pos.strict_add(align.strict_sub(offset)); + } + + let ptr = heap_pos as *mut u8; + // Panic on overflow. We don't want to wrap around, and overwrite stack etc. // (We could also return a null pointer, but only malicious programs would ever hit this.) - heap_pos = heap_pos.add(layout.size()); + heap_pos = heap_pos.strict_add(layout.size()); HEAP.next_alloc = heap_pos; ptr @@ -35,14 +37,13 @@ unsafe impl GlobalAlloc for SimpleAllocator { unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} } -extern "C" { - /// The address of this variable is the start of the heap (growing upwards). - /// - /// It is defined in the linker script. - static mut _sheap: u8; -} - #[global_allocator] +// We initialize `next_alloc` to 0xFFFF_FFFF to indicate that the heap has not been initialized. +// The value is chosen to make any premature allocation fail. static mut HEAP: SimpleAllocator = SimpleAllocator { - next_alloc: &raw mut _sheap, + next_alloc: 0xFFFF_FFFF, }; + +pub unsafe fn init_heap() { + HEAP.next_alloc = core::ptr::from_ref::(&crate::_sheap).cast::() as usize; +} diff --git a/ceno_rt/src/lib.rs b/ceno_rt/src/lib.rs index c27f02145..4440cbcc0 100644 --- a/ceno_rt/src/lib.rs +++ b/ceno_rt/src/lib.rs @@ -82,14 +82,19 @@ macro_rules! entry { /// _start_rust is called by the assembly entry point and it calls the Rust main(). #[no_mangle] unsafe extern "C" fn _start_rust() -> ! { - extern "C" { - fn bespoke_entrypoint(); + allocator::init_heap(); + { + extern "C" { + fn bespoke_entrypoint(); + } + bespoke_entrypoint(); } - bespoke_entrypoint(); halt(0) } extern "C" { // The address of this variable is the start of the stack (growing downwards). static _stack_start: u8; + // The address of this variable is the start of the heap (growing upwards). + static _sheap: u8; } From 42da8da2b75c98a413f8a0da47488b3091141c55 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 16:56:37 +0800 Subject: [PATCH 21/44] Doc --- ceno_rt/src/mmio.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ceno_rt/src/mmio.rs b/ceno_rt/src/mmio.rs index af38d6d35..3994750b5 100644 --- a/ceno_rt/src/mmio.rs +++ b/ceno_rt/src/mmio.rs @@ -5,7 +5,9 @@ use rkyv::{Portable, api::high::HighValidator, bytecheck::CheckBytes, rancor::Fa use core::slice::from_raw_parts; extern "C" { - // The address of this variable is the start of the hints ROM. + /// The address of this variable is the start of the hints ROM. + /// + /// It is defined in the linker script. static _hints_start: u8; } From 8fdb803140992e38e5a90c0f7764f65d6741cfed Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 17:13:07 +0800 Subject: [PATCH 22/44] Don't hardcode the size of the region --- ceno_rt/ceno_link.x | 1 + ceno_rt/src/mmio.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ceno_rt/ceno_link.x b/ceno_rt/ceno_link.x index 2747b8109..4c2e9e257 100644 --- a/ceno_rt/ceno_link.x +++ b/ceno_rt/ceno_link.x @@ -1,6 +1,7 @@ _stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK); _hints_start = ORIGIN(REGION_HINTS); +_hints_end = ORIGIN(REGION_HINTS) + LENGTH(REGION_HINTS); SECTIONS { diff --git a/ceno_rt/src/mmio.rs b/ceno_rt/src/mmio.rs index 3994750b5..3a7a44557 100644 --- a/ceno_rt/src/mmio.rs +++ b/ceno_rt/src/mmio.rs @@ -9,6 +9,7 @@ extern "C" { /// /// It is defined in the linker script. static _hints_start: u8; + static _hints_end: u8; } static mut NEXT_HINT_LEN_AT: *const u8 = &raw const _hints_start; @@ -18,7 +19,12 @@ pub fn read_slice<'a>() -> &'a [u8] { let len: u32 = core::ptr::read(NEXT_HINT_LEN_AT as *const u32); NEXT_HINT_LEN_AT = NEXT_HINT_LEN_AT.wrapping_add(4); - &from_raw_parts(&_hints_start, 1 << 30)[..len as usize] + let hints_region = { + let total_length = (&raw const _hints_end).offset_from(&_hints_start) as usize; + from_raw_parts(&_hints_start, total_length) + }; + + &hints_region[..len as usize] } } From 1e16d24f9417b2e41e4e18f500e27b2491725009 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 17:13:37 +0800 Subject: [PATCH 23/44] Simpler --- ceno_rt/src/mmio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ceno_rt/src/mmio.rs b/ceno_rt/src/mmio.rs index 3a7a44557..1f7bddc44 100644 --- a/ceno_rt/src/mmio.rs +++ b/ceno_rt/src/mmio.rs @@ -17,7 +17,7 @@ static mut NEXT_HINT_LEN_AT: *const u8 = &raw const _hints_start; pub fn read_slice<'a>() -> &'a [u8] { unsafe { let len: u32 = core::ptr::read(NEXT_HINT_LEN_AT as *const u32); - NEXT_HINT_LEN_AT = NEXT_HINT_LEN_AT.wrapping_add(4); + NEXT_HINT_LEN_AT = NEXT_HINT_LEN_AT.add(4); let hints_region = { let total_length = (&raw const _hints_end).offset_from(&_hints_start) as usize; From 2f78d46a78cb1a939e8ffaec04e84a401e2d416e Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 17:24:01 +0800 Subject: [PATCH 24/44] Deduplicate --- ceno_emul/src/host_utils.rs | 32 ++++++++++++++++++++++++++++ ceno_emul/src/lib.rs | 2 ++ ceno_emul/tests/test_elf.rs | 42 +++++++------------------------------ ceno_host/src/lib.rs | 33 +---------------------------- 4 files changed, 42 insertions(+), 67 deletions(-) create mode 100644 ceno_emul/src/host_utils.rs diff --git a/ceno_emul/src/host_utils.rs b/ceno_emul/src/host_utils.rs new file mode 100644 index 000000000..d29a5d825 --- /dev/null +++ b/ceno_emul/src/host_utils.rs @@ -0,0 +1,32 @@ +use crate::{ByteAddr, EmuContext, VMState}; + +const WORD_SIZE: usize = 4; +const INFO_OUT_ADDR: u32 = 0xC000_0000; + +pub fn read_all_messages(state: &VMState) -> Vec { + let mut all_messages = Vec::new(); + let mut word_offset = 0; + loop { + let out = read_message(state, word_offset); + if out.is_empty() { + break; + } + word_offset += out.len().div_ceil(WORD_SIZE) as u32 + 1; + all_messages.push(out); + } + all_messages +} + +fn read_message(state: &VMState, word_offset: u32) -> String { + let out_addr = ByteAddr(INFO_OUT_ADDR).waddr() + word_offset; + let byte_len = state.peek_memory(out_addr); + let word_len_up = byte_len.div_ceil(4); + + let mut info_out = Vec::with_capacity(WORD_SIZE * word_len_up as usize); + for i in 1..1 + word_len_up { + let value = state.peek_memory(out_addr + i); + info_out.extend_from_slice(&value.to_le_bytes()); + } + info_out.truncate(byte_len as usize); + String::from_utf8_lossy(&info_out).to_string() +} diff --git a/ceno_emul/src/lib.rs b/ceno_emul/src/lib.rs index c734b1794..fd18f4c61 100644 --- a/ceno_emul/src/lib.rs +++ b/ceno_emul/src/lib.rs @@ -19,3 +19,5 @@ pub use elf::Program; mod rv32im_encode; pub use rv32im_encode::encode_rv32; + +pub mod host_utils; diff --git a/ceno_emul/tests/test_elf.rs b/ceno_emul/tests/test_elf.rs index ca7a14c1c..bc144d401 100644 --- a/ceno_emul/tests/test_elf.rs +++ b/ceno_emul/tests/test_elf.rs @@ -1,5 +1,8 @@ use anyhow::Result; -use ceno_emul::{ByteAddr, CENO_PLATFORM, EmuContext, InsnKind, Platform, StepRecord, VMState}; +use ceno_emul::{ + CENO_PLATFORM, EmuContext, InsnKind, Platform, StepRecord, VMState, + host_utils::read_all_messages, +}; #[test] fn test_ceno_rt_mini() -> Result<()> { @@ -65,10 +68,10 @@ fn test_ceno_rt_io() -> Result<()> { let all_messages = read_all_messages(&state); for msg in &all_messages { - print!("{}", String::from_utf8_lossy(msg)); + print!("{msg}"); } - assert_eq!(&all_messages[0], "📜📜📜 Hello, World!\n".as_bytes()); - assert_eq!(&all_messages[1], "🌏🌍🌎\n".as_bytes()); + assert_eq!(&all_messages[0], "📜📜📜 Hello, World!\n"); + assert_eq!(&all_messages[1], "🌏🌍🌎\n"); Ok(()) } @@ -77,34 +80,3 @@ fn run(state: &mut VMState) -> Result> { eprintln!("Emulator ran for {} steps.", steps.len()); Ok(steps) } - -const WORD_SIZE: usize = 4; -const INFO_OUT_ADDR: u32 = 0xC000_0000; - -fn read_all_messages(state: &VMState) -> Vec> { - let mut all_messages = Vec::new(); - let mut word_offset = 0; - loop { - let out = read_message(state, word_offset); - if out.is_empty() { - break; - } - word_offset += out.len().div_ceil(WORD_SIZE) as u32 + 1; - all_messages.push(out); - } - all_messages -} - -fn read_message(state: &VMState, word_offset: u32) -> Vec { - let out_addr = ByteAddr(INFO_OUT_ADDR).waddr() + word_offset; - let byte_len = state.peek_memory(out_addr); - let word_len_up = byte_len.div_ceil(4); - - let mut info_out = Vec::with_capacity(WORD_SIZE * word_len_up as usize); - for i in 1..1 + word_len_up { - let value = state.peek_memory(out_addr + i); - info_out.extend_from_slice(&value.to_le_bytes()); - } - info_out.truncate(byte_len as usize); - info_out -} diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index 134225015..92e52ccca 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -1,7 +1,7 @@ use std::iter::zip; use anyhow::Result; -use ceno_emul::{ByteAddr, EmuContext, IterAddresses, Platform, VMState}; +use ceno_emul::{IterAddresses, Platform, VMState, host_utils::read_all_messages}; use itertools::izip; use rkyv::{ Serialize, api::high::HighSerializer, rancor::Error, ser::allocator::ArenaHandle, to_bytes, @@ -72,37 +72,6 @@ impl CenoStdin { // TODO(Matthias): much of this is copied from `test_elf.rs` in Ceno. These are generally useful // functions, so we should make them available for both crates, instead of copy-and-pasting here. -const WORD_SIZE: usize = 4; -const INFO_OUT_ADDR: u32 = 0xC000_0000; - -fn read_all_messages(state: &VMState) -> Vec { - let mut all_messages = Vec::new(); - let mut word_offset = 0; - loop { - let out = read_message(state, word_offset); - if out.is_empty() { - break; - } - word_offset += out.len().div_ceil(WORD_SIZE) as u32 + 1; - all_messages.push(out); - } - all_messages -} - -fn read_message(state: &VMState, word_offset: u32) -> String { - let out_addr = ByteAddr(INFO_OUT_ADDR).waddr() + word_offset; - let byte_len = state.peek_memory(out_addr); - let word_len_up = byte_len.div_ceil(4); - - let mut info_out = Vec::with_capacity(WORD_SIZE * word_len_up as usize); - for i in 1..1 + word_len_up { - let value = state.peek_memory(out_addr + i); - info_out.extend_from_slice(&value.to_le_bytes()); - } - info_out.truncate(byte_len as usize); - String::from_utf8_lossy(&info_out).to_string() -} - // TODO(Matthias): also return exit code (if any) pub fn run(platform: Platform, elf: &[u8], hints: &CenoStdin) -> Vec { let hints: Vec = hints.finalise(); From 39280bf5cb5df3f1e821c9072e8f149b08a912e9 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 17:24:34 +0800 Subject: [PATCH 25/44] Done TODO --- ceno_host/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index 92e52ccca..8dbdab0c3 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -69,10 +69,6 @@ impl CenoStdin { } } -// TODO(Matthias): much of this is copied from `test_elf.rs` in Ceno. These are generally useful -// functions, so we should make them available for both crates, instead of copy-and-pasting here. - -// TODO(Matthias): also return exit code (if any) pub fn run(platform: Platform, elf: &[u8], hints: &CenoStdin) -> Vec { let hints: Vec = hints.finalise(); From 31805f68635f7310b2c889782b5ab24d8179e156 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 17:46:43 +0800 Subject: [PATCH 26/44] Strings --- ceno_emul/src/addr.rs | 13 +++++++++++++ ceno_emul/src/host_utils.rs | 18 ++++++++++-------- ceno_emul/src/lib.rs | 1 + 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/ceno_emul/src/addr.rs b/ceno_emul/src/addr.rs index ff8f7c0a0..d9069e1a0 100644 --- a/ceno_emul/src/addr.rs +++ b/ceno_emul/src/addr.rs @@ -16,6 +16,7 @@ use std::{ fmt, + iter::Step, ops::{self, Range}, }; @@ -106,6 +107,18 @@ impl WordAddr { } } +impl Step for WordAddr { + fn steps_between(start: &Self, end: &Self) -> (usize, Option) { + u32::steps_between(&start.0, &end.0) + } + fn forward_checked(start: Self, count: usize) -> Option { + u32::forward_checked(start.0, count).map(Self) + } + fn backward_checked(start: Self, count: usize) -> Option { + u32::backward_checked(start.0, count).map(Self) + } +} + impl fmt::Debug for ByteAddr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "0x{:08x}", self.0) diff --git a/ceno_emul/src/host_utils.rs b/ceno_emul/src/host_utils.rs index d29a5d825..73c501b1b 100644 --- a/ceno_emul/src/host_utils.rs +++ b/ceno_emul/src/host_utils.rs @@ -19,14 +19,16 @@ pub fn read_all_messages(state: &VMState) -> Vec { fn read_message(state: &VMState, word_offset: u32) -> String { let out_addr = ByteAddr(INFO_OUT_ADDR).waddr() + word_offset; - let byte_len = state.peek_memory(out_addr); + let byte_len = state.peek_memory(out_addr) as usize; let word_len_up = byte_len.div_ceil(4); - let mut info_out = Vec::with_capacity(WORD_SIZE * word_len_up as usize); - for i in 1..1 + word_len_up { - let value = state.peek_memory(out_addr + i); - info_out.extend_from_slice(&value.to_le_bytes()); - } - info_out.truncate(byte_len as usize); - String::from_utf8_lossy(&info_out).to_string() + String::from_utf8_lossy( + &(out_addr + 1_usize..) + .take(word_len_up) + .map(|memory| state.peek_memory(memory)) + .flat_map(u32::to_le_bytes) + .take(byte_len) + .collect::>(), + ) + .to_string() } diff --git a/ceno_emul/src/lib.rs b/ceno_emul/src/lib.rs index fd18f4c61..c18fc232b 100644 --- a/ceno_emul/src/lib.rs +++ b/ceno_emul/src/lib.rs @@ -1,4 +1,5 @@ #![deny(clippy::cargo)] +#![feature(step_trait)] mod addr; pub use addr::*; From 5091d3dd7896e7ceb25f0d655eeb3afc0b513fbd Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 17:56:06 +0800 Subject: [PATCH 27/44] Just for fun --- ceno_emul/src/host_utils.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ceno_emul/src/host_utils.rs b/ceno_emul/src/host_utils.rs index 73c501b1b..ec2f1685d 100644 --- a/ceno_emul/src/host_utils.rs +++ b/ceno_emul/src/host_utils.rs @@ -1,24 +1,24 @@ -use crate::{ByteAddr, EmuContext, VMState}; +use std::iter::from_fn; + +use crate::{ByteAddr, EmuContext, VMState, WordAddr}; const WORD_SIZE: usize = 4; -const INFO_OUT_ADDR: u32 = 0xC000_0000; +const INFO_OUT_ADDR: WordAddr = ByteAddr(0xC000_0000).waddr(); pub fn read_all_messages(state: &VMState) -> Vec { - let mut all_messages = Vec::new(); - let mut word_offset = 0; - loop { - let out = read_message(state, word_offset); - if out.is_empty() { - break; + let mut offset: WordAddr = WordAddr::from(0); + from_fn(move || match read_message(state, offset) { + out if out.is_empty() => None, + out => { + offset += out.len().div_ceil(WORD_SIZE) as u32 + 1; + Some(out) } - word_offset += out.len().div_ceil(WORD_SIZE) as u32 + 1; - all_messages.push(out); - } - all_messages + }) + .collect() } -fn read_message(state: &VMState, word_offset: u32) -> String { - let out_addr = ByteAddr(INFO_OUT_ADDR).waddr() + word_offset; +fn read_message(state: &VMState, offset: WordAddr) -> String { + let out_addr = INFO_OUT_ADDR + offset; let byte_len = state.peek_memory(out_addr) as usize; let word_len_up = byte_len.div_ceil(4); From 10de0da6d94644fac0e4c6c7382e4bbb55c32d5b Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Tue, 10 Dec 2024 17:57:01 +0800 Subject: [PATCH 28/44] Simpler --- ceno_emul/src/host_utils.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ceno_emul/src/host_utils.rs b/ceno_emul/src/host_utils.rs index ec2f1685d..460635f83 100644 --- a/ceno_emul/src/host_utils.rs +++ b/ceno_emul/src/host_utils.rs @@ -20,11 +20,9 @@ pub fn read_all_messages(state: &VMState) -> Vec { fn read_message(state: &VMState, offset: WordAddr) -> String { let out_addr = INFO_OUT_ADDR + offset; let byte_len = state.peek_memory(out_addr) as usize; - let word_len_up = byte_len.div_ceil(4); String::from_utf8_lossy( &(out_addr + 1_usize..) - .take(word_len_up) .map(|memory| state.peek_memory(memory)) .flat_map(u32::to_le_bytes) .take(byte_len) From ea77dbdae448cd6a8b905847479b4d57ec9796ad Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 13 Dec 2024 15:09:45 +0800 Subject: [PATCH 29/44] Show hint example --- {ceno_emul => ceno_host}/tests/test_elf.rs | 16 ++++++++++++++++ guest/examples/examples/hints.rs | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+) rename {ceno_emul => ceno_host}/tests/test_elf.rs (83%) create mode 100644 guest/examples/examples/hints.rs diff --git a/ceno_emul/tests/test_elf.rs b/ceno_host/tests/test_elf.rs similarity index 83% rename from ceno_emul/tests/test_elf.rs rename to ceno_host/tests/test_elf.rs index b8eb7eff9..17092cbaa 100644 --- a/ceno_emul/tests/test_elf.rs +++ b/ceno_host/tests/test_elf.rs @@ -3,6 +3,8 @@ use ceno_emul::{ CENO_PLATFORM, EmuContext, InsnKind, Platform, StepRecord, VMState, host_utils::read_all_messages, }; +use ceno_host::CenoStdin; +use itertools::enumerate; #[test] fn test_ceno_rt_mini() -> Result<()> { @@ -75,6 +77,20 @@ fn test_ceno_rt_io() -> Result<()> { Ok(()) } +#[test] +fn test_hints() { + let mut hints = CenoStdin::default(); + hints.write(&"This is my hint string.".to_string()).unwrap(); + hints.write(&1997_u32).unwrap(); + hints.write(&1999_u32).unwrap(); + + let all_messages = ceno_host::run(CENO_PLATFORM, ceno_examples::hints, &hints); + for (i, msg) in enumerate(&all_messages) { + println!("{i}: {msg}"); + } + assert_eq!(all_messages[0], "3992003"); +} + fn run(state: &mut VMState) -> Result> { let steps = state.iter_until_halt().collect::>>()?; eprintln!("Emulator ran for {} steps.", steps.len()); diff --git a/guest/examples/examples/hints.rs b/guest/examples/examples/hints.rs new file mode 100644 index 000000000..cf880f19f --- /dev/null +++ b/guest/examples/examples/hints.rs @@ -0,0 +1,20 @@ +#![no_main] +#![no_std] + +extern crate ceno_rt; +use ceno_rt::println; +use core::fmt::Write; +use rkyv::{Archived, string::ArchivedString}; + +ceno_rt::entry!(main); +fn main() { + let msg: &ArchivedString = ceno_rt::read(); + + let a: &Archived = ceno_rt::read(); + let b: &Archived = ceno_rt::read(); + let product: u32 = a * b; + + assert_eq!(product, 3992003); + println!("{product}"); + println!("This message is a hint: {msg}"); +} From c438b432e73dcd64d582ab41be358a9b3663383a Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 13 Dec 2024 15:10:38 +0800 Subject: [PATCH 30/44] Formatting --- Cargo.lock | 2 +- ceno_emul/Cargo.toml | 3 --- ceno_host/Cargo.toml | 1 + examples-builder/build.rs | 1 + guest/Cargo.lock | 1 + guest/examples/Cargo.toml | 4 ++++ 6 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03c1c4f69..90a1a0f4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -256,7 +256,6 @@ name = "ceno_emul" version = "0.1.0" dependencies = [ "anyhow", - "ceno-examples", "elf", "itertools 0.13.0", "num-derive", @@ -272,6 +271,7 @@ name = "ceno_host" version = "0.1.0" dependencies = [ "anyhow", + "ceno-examples", "ceno_emul", "itertools 0.13.0", "rand", diff --git a/ceno_emul/Cargo.toml b/ceno_emul/Cargo.toml index 573419cb1..c566df0f5 100644 --- a/ceno_emul/Cargo.toml +++ b/ceno_emul/Cargo.toml @@ -20,9 +20,6 @@ strum.workspace = true strum_macros.workspace = true tracing.workspace = true -[dev-dependencies] -ceno-examples = { path = "../examples-builder" } - [features] default = ["forbid_overflow"] forbid_overflow = [] diff --git a/ceno_host/Cargo.toml b/ceno_host/Cargo.toml index e8907cef6..ad2b6e044 100644 --- a/ceno_host/Cargo.toml +++ b/ceno_host/Cargo.toml @@ -16,4 +16,5 @@ itertools.workspace = true rkyv = { version = "0.8.9", default-features = false, features = ["alloc", "bytecheck"] } [dev-dependencies] +ceno-examples = { path = "../examples-builder" } rand.workspace = true diff --git a/examples-builder/build.rs b/examples-builder/build.rs index 0e8d90441..d11c176cf 100644 --- a/examples-builder/build.rs +++ b/examples-builder/build.rs @@ -14,6 +14,7 @@ const EXAMPLES: &[&str] = &[ "ceno_rt_mem", "ceno_rt_mini", "ceno_rt_panic", + "hints", ]; const CARGO_MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR"); diff --git a/guest/Cargo.lock b/guest/Cargo.lock index 40ea494f1..62c5b6521 100644 --- a/guest/Cargo.lock +++ b/guest/Cargo.lock @@ -50,6 +50,7 @@ name = "examples" version = "0.1.0" dependencies = [ "ceno_rt", + "rkyv", ] [[package]] diff --git a/guest/examples/Cargo.toml b/guest/examples/Cargo.toml index 397e743b1..24b25d313 100644 --- a/guest/examples/Cargo.toml +++ b/guest/examples/Cargo.toml @@ -11,3 +11,7 @@ version.workspace = true [dependencies] ceno_rt = { path = "../ceno_rt" } +rkyv = { version = "0.8", default-features = false, features = [ + "alloc", + "bytecheck", +] } From 9a746bc9d5009b26c6d194577f65df33c0d4d19c Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 13 Dec 2024 15:11:15 +0800 Subject: [PATCH 31/44] Remove pedantic --- ceno_emul/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ceno_emul/src/lib.rs b/ceno_emul/src/lib.rs index 561fd7bda..ba4195815 100644 --- a/ceno_emul/src/lib.rs +++ b/ceno_emul/src/lib.rs @@ -1,5 +1,4 @@ #![deny(clippy::cargo)] -// #![deny(clippy::pedantic)] #![feature(step_trait)] mod addr; pub use addr::*; From 9d7626865162fb99580df588375f9b85d2db8ca2 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 13 Dec 2024 15:13:48 +0800 Subject: [PATCH 32/44] Use bool as test case --- ceno_host/tests/test_elf.rs | 10 ++++++---- guest/examples/examples/hints.rs | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ceno_host/tests/test_elf.rs b/ceno_host/tests/test_elf.rs index 17092cbaa..ceabe2413 100644 --- a/ceno_host/tests/test_elf.rs +++ b/ceno_host/tests/test_elf.rs @@ -78,17 +78,19 @@ fn test_ceno_rt_io() -> Result<()> { } #[test] -fn test_hints() { +fn test_hints() -> Result<()> { let mut hints = CenoStdin::default(); - hints.write(&"This is my hint string.".to_string()).unwrap(); - hints.write(&1997_u32).unwrap(); - hints.write(&1999_u32).unwrap(); + hints.write(&true)?; + hints.write(&"This is my hint string.".to_string())?; + hints.write(&1997_u32)?; + hints.write(&1999_u32)?; let all_messages = ceno_host::run(CENO_PLATFORM, ceno_examples::hints, &hints); for (i, msg) in enumerate(&all_messages) { println!("{i}: {msg}"); } assert_eq!(all_messages[0], "3992003"); + Ok(()) } fn run(state: &mut VMState) -> Result> { diff --git a/guest/examples/examples/hints.rs b/guest/examples/examples/hints.rs index cf880f19f..090c439a7 100644 --- a/guest/examples/examples/hints.rs +++ b/guest/examples/examples/hints.rs @@ -8,6 +8,8 @@ use rkyv::{Archived, string::ArchivedString}; ceno_rt::entry!(main); fn main() { + let condition: &bool = ceno_rt::read(); + assert!(*condition); let msg: &ArchivedString = ceno_rt::read(); let a: &Archived = ceno_rt::read(); From 863f3ad943e07da61ff04a7ee8da24213a80435d Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 13 Dec 2024 15:35:22 +0800 Subject: [PATCH 33/44] Suggestion --- ceno_host/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index 8dbdab0c3..149a525de 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -53,10 +53,7 @@ impl CenoStdin { ]); for (offset, item) in izip!(offsets, &self.items) { buf.extend_from_slice(item); - buf.extend_from_slice(&vec![ - 0; - buf.len().next_multiple_of(RKYV_ALIGNMENT) - buf.len() - ]); + buf.resize(buf.len().next_multiple_of(RKYV_ALIGNMENT), 0); assert_eq!( buf.len(), (offset as usize).next_multiple_of(RKYV_ALIGNMENT) From 4d8f9243c426b49db23c9ce9a355729a4264699c Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 13 Dec 2024 18:14:28 +0800 Subject: [PATCH 34/44] Reshuffle crates --- Cargo.toml | 2 +- {guest => ceno_rt}/.cargo/config.toml | 0 ceno_rt/Cargo.lock | 93 ++++++++++++++++ ceno_rt/Cargo.toml | 13 +++ {guest/ceno_rt => ceno_rt}/README.md | 0 {guest/ceno_rt => ceno_rt}/build.rs | 0 {guest/ceno_rt => ceno_rt}/ceno_link.x | 0 {guest/ceno_rt => ceno_rt}/memory.x | 0 {guest/ceno_rt => ceno_rt}/src/allocator.rs | 0 {guest/ceno_rt => ceno_rt}/src/io.rs | 0 {guest/ceno_rt => ceno_rt}/src/lib.rs | 0 {guest/ceno_rt => ceno_rt}/src/params.rs | 0 examples-builder/build.rs | 8 +- examples/.cargo/config.toml | 1 + examples/Cargo.lock | 100 ++++++++++++++++++ examples/Cargo.toml | 13 +++ .../examples/ceno_rt_alloc.rs | 0 .../examples/ceno_rt_io.rs | 0 .../examples/ceno_rt_mem.rs | 0 .../examples/ceno_rt_mini.rs | 0 .../examples/ceno_rt_panic.rs | 0 guest/ceno_rt/Cargo.toml | 13 --- guest/examples/Cargo.toml | 13 --- 23 files changed, 225 insertions(+), 31 deletions(-) rename {guest => ceno_rt}/.cargo/config.toml (100%) create mode 100644 ceno_rt/Cargo.lock create mode 100644 ceno_rt/Cargo.toml rename {guest/ceno_rt => ceno_rt}/README.md (100%) rename {guest/ceno_rt => ceno_rt}/build.rs (100%) rename {guest/ceno_rt => ceno_rt}/ceno_link.x (100%) rename {guest/ceno_rt => ceno_rt}/memory.x (100%) rename {guest/ceno_rt => ceno_rt}/src/allocator.rs (100%) rename {guest/ceno_rt => ceno_rt}/src/io.rs (100%) rename {guest/ceno_rt => ceno_rt}/src/lib.rs (100%) rename {guest/ceno_rt => ceno_rt}/src/params.rs (100%) create mode 120000 examples/.cargo/config.toml create mode 100644 examples/Cargo.lock create mode 100644 examples/Cargo.toml rename {guest/examples => examples}/examples/ceno_rt_alloc.rs (100%) rename {guest/examples => examples}/examples/ceno_rt_io.rs (100%) rename {guest/examples => examples}/examples/ceno_rt_mem.rs (100%) rename {guest/examples => examples}/examples/ceno_rt_mini.rs (100%) rename {guest/examples => examples}/examples/ceno_rt_panic.rs (100%) delete mode 100644 guest/ceno_rt/Cargo.toml delete mode 100644 guest/examples/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index 93cabd8d9..2fb832769 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -exclude = ["guest"] +exclude = ["ceno_rt", "examples"] members = [ "ceno_emul", "examples-builder", diff --git a/guest/.cargo/config.toml b/ceno_rt/.cargo/config.toml similarity index 100% rename from guest/.cargo/config.toml rename to ceno_rt/.cargo/config.toml diff --git a/ceno_rt/Cargo.lock b/ceno_rt/Cargo.lock new file mode 100644 index 000000000..feb0692ae --- /dev/null +++ b/ceno_rt/Cargo.lock @@ -0,0 +1,93 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ceno_rt" +version = "0.1.0" +dependencies = [ + "riscv", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "riscv" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7" +dependencies = [ + "critical-section", + "embedded-hal", + "paste", + "riscv-macros", + "riscv-pac", +] + +[[package]] +name = "riscv-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "riscv-pac" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" diff --git a/ceno_rt/Cargo.toml b/ceno_rt/Cargo.toml new file mode 100644 index 000000000..2ba43c74a --- /dev/null +++ b/ceno_rt/Cargo.toml @@ -0,0 +1,13 @@ +[package] +categories = ["cryptography", "zk", "blockchain", "ceno"] +description = "Ceno runtime library" +edition = "2021" +keywords = ["cryptography", "zk", "blockchain", "ceno"] +license = "MIT OR Apache-2.0" +name = "ceno_rt" +readme = "README.md" +repository = "https://github.com/scroll-tech/ceno" +version = "0.1.0" + +[dependencies] +riscv = "0.12" diff --git a/guest/ceno_rt/README.md b/ceno_rt/README.md similarity index 100% rename from guest/ceno_rt/README.md rename to ceno_rt/README.md diff --git a/guest/ceno_rt/build.rs b/ceno_rt/build.rs similarity index 100% rename from guest/ceno_rt/build.rs rename to ceno_rt/build.rs diff --git a/guest/ceno_rt/ceno_link.x b/ceno_rt/ceno_link.x similarity index 100% rename from guest/ceno_rt/ceno_link.x rename to ceno_rt/ceno_link.x diff --git a/guest/ceno_rt/memory.x b/ceno_rt/memory.x similarity index 100% rename from guest/ceno_rt/memory.x rename to ceno_rt/memory.x diff --git a/guest/ceno_rt/src/allocator.rs b/ceno_rt/src/allocator.rs similarity index 100% rename from guest/ceno_rt/src/allocator.rs rename to ceno_rt/src/allocator.rs diff --git a/guest/ceno_rt/src/io.rs b/ceno_rt/src/io.rs similarity index 100% rename from guest/ceno_rt/src/io.rs rename to ceno_rt/src/io.rs diff --git a/guest/ceno_rt/src/lib.rs b/ceno_rt/src/lib.rs similarity index 100% rename from guest/ceno_rt/src/lib.rs rename to ceno_rt/src/lib.rs diff --git a/guest/ceno_rt/src/params.rs b/ceno_rt/src/params.rs similarity index 100% rename from guest/ceno_rt/src/params.rs rename to ceno_rt/src/params.rs diff --git a/examples-builder/build.rs b/examples-builder/build.rs index 0e8d90441..7ea9b9628 100644 --- a/examples-builder/build.rs +++ b/examples-builder/build.rs @@ -26,7 +26,7 @@ fn build_elfs() { // See git history for an attempt to do this. let output = Command::new("cargo") .args(["build", "--release", "--examples"]) - .current_dir("../guest/examples") + .current_dir("../examples") .env_clear() .envs(std::env::vars().filter(|x| !x.0.starts_with("CARGO_"))) .output() @@ -41,11 +41,11 @@ fn build_elfs() { dest, r#"#[allow(non_upper_case_globals)] pub const {example}: &[u8] = - include_bytes!(r"{CARGO_MANIFEST_DIR}/../guest/target/riscv32im-unknown-none-elf/release/examples/{example}");"# + include_bytes!(r"{CARGO_MANIFEST_DIR}/../examples/target/riscv32im-unknown-none-elf/release/examples/{example}");"# ).expect("failed to write vars.rs"); } - let input_path = "../guest/"; - let elfs_path = "../guest/target/riscv32im-unknown-none-elf/release/examples/"; + let input_path = "../examples/"; + let elfs_path = "../examples/target/riscv32im-unknown-none-elf/release/examples/"; println!("cargo:rerun-if-changed={input_path}"); println!("cargo:rerun-if-changed={elfs_path}"); diff --git a/examples/.cargo/config.toml b/examples/.cargo/config.toml new file mode 120000 index 000000000..bade0c189 --- /dev/null +++ b/examples/.cargo/config.toml @@ -0,0 +1 @@ +../../ceno_rt/.cargo/config.toml \ No newline at end of file diff --git a/examples/Cargo.lock b/examples/Cargo.lock new file mode 100644 index 000000000..84c6c3ab6 --- /dev/null +++ b/examples/Cargo.lock @@ -0,0 +1,100 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ceno_rt" +version = "0.1.0" +dependencies = [ + "riscv", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "examples" +version = "0.1.0" +dependencies = [ + "ceno_rt", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "riscv" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7" +dependencies = [ + "critical-section", + "embedded-hal", + "paste", + "riscv-macros", + "riscv-pac", +] + +[[package]] +name = "riscv-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "riscv-pac" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" diff --git a/examples/Cargo.toml b/examples/Cargo.toml new file mode 100644 index 000000000..b3751d1f3 --- /dev/null +++ b/examples/Cargo.toml @@ -0,0 +1,13 @@ +[package] +categories = ["cryptography", "zk", "blockchain", "ceno"] +description = "Ceno RiscV guest examples" +edition = "2021" +keywords = ["cryptography", "zk", "blockchain", "ceno"] +license = "MIT OR Apache-2.0" +name = "examples" +readme = "README.md" +repository = "https://github.com/scroll-tech/ceno" +version = "0.1.0" + +[dependencies] +ceno_rt = { path = "../ceno_rt" } diff --git a/guest/examples/examples/ceno_rt_alloc.rs b/examples/examples/ceno_rt_alloc.rs similarity index 100% rename from guest/examples/examples/ceno_rt_alloc.rs rename to examples/examples/ceno_rt_alloc.rs diff --git a/guest/examples/examples/ceno_rt_io.rs b/examples/examples/ceno_rt_io.rs similarity index 100% rename from guest/examples/examples/ceno_rt_io.rs rename to examples/examples/ceno_rt_io.rs diff --git a/guest/examples/examples/ceno_rt_mem.rs b/examples/examples/ceno_rt_mem.rs similarity index 100% rename from guest/examples/examples/ceno_rt_mem.rs rename to examples/examples/ceno_rt_mem.rs diff --git a/guest/examples/examples/ceno_rt_mini.rs b/examples/examples/ceno_rt_mini.rs similarity index 100% rename from guest/examples/examples/ceno_rt_mini.rs rename to examples/examples/ceno_rt_mini.rs diff --git a/guest/examples/examples/ceno_rt_panic.rs b/examples/examples/ceno_rt_panic.rs similarity index 100% rename from guest/examples/examples/ceno_rt_panic.rs rename to examples/examples/ceno_rt_panic.rs diff --git a/guest/ceno_rt/Cargo.toml b/guest/ceno_rt/Cargo.toml deleted file mode 100644 index dfdc87ad2..000000000 --- a/guest/ceno_rt/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -categories.workspace = true -description = "Ceno runtime library" -edition.workspace = true -keywords.workspace = true -license.workspace = true -name = "ceno_rt" -readme = "README.md" -repository.workspace = true -version.workspace = true - -[dependencies] -riscv = "0.12" diff --git a/guest/examples/Cargo.toml b/guest/examples/Cargo.toml deleted file mode 100644 index 397e743b1..000000000 --- a/guest/examples/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -categories.workspace = true -description = "Ceno RiscV guest examples" -edition.workspace = true -keywords.workspace = true -license.workspace = true -name = "examples" -readme = "README.md" -repository.workspace = true -version.workspace = true - -[dependencies] -ceno_rt = { path = "../ceno_rt" } From 5a95f70e0a12456f5562ea7792c795fd3dd85f77 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 13 Dec 2024 18:50:23 +0800 Subject: [PATCH 35/44] Fix --- ceno_host/src/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index 149a525de..49b58f3ee 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -1,7 +1,7 @@ -use std::iter::zip; +use std::{collections::HashSet, iter::zip, sync::Arc}; use anyhow::Result; -use ceno_emul::{IterAddresses, Platform, VMState, host_utils::read_all_messages}; +use ceno_emul::{IterAddresses, Platform, Program, VMState, host_utils::read_all_messages}; use itertools::izip; use rkyv::{ Serialize, api::high::HighSerializer, rancor::Error, ser::allocator::ArenaHandle, to_bytes, @@ -67,11 +67,18 @@ impl CenoStdin { } pub fn run(platform: Platform, elf: &[u8], hints: &CenoStdin) -> Vec { + let program = Program::load_elf(elf, u32::MAX).unwrap(); + let platform = Platform { + prog_data: Some(program.image.keys().copied().collect::>()), + ..platform + }; + let hints: Vec = hints.finalise(); + let hints_range = platform.hints.clone(); - let mut state = VMState::new_from_elf(platform.clone(), elf).expect("Failed to load ELF"); + let mut state = VMState::new(platform, Arc::new(program)); - for (addr, value) in zip(platform.hints.iter_addresses(), hints) { + for (addr, value) in zip(hints_range.iter_addresses(), hints) { state.init_memory(addr.into(), value); } From 3fa5d49ca3e5a3c4f1472871202ec4040f124dac Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 13 Dec 2024 19:02:18 +0800 Subject: [PATCH 36/44] Adapt cache --- .github/workflows/integration.yml | 3 ++- .github/workflows/lints.yml | 3 ++- .github/workflows/tests.yml | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 8bcc5dfed..1150da037 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -47,7 +47,8 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - guest/target/ + example/target/ + ceno_rt/target/ key: integration-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - uses: dtolnay/rust-toolchain@nightly diff --git a/.github/workflows/lints.yml b/.github/workflows/lints.yml index 1f8d41b0b..f738f7183 100644 --- a/.github/workflows/lints.yml +++ b/.github/workflows/lints.yml @@ -35,7 +35,8 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - guest/target/ + ceno_rt/target/ + example/target/ key: lint-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} restore-keys: lint-${{ runner.os }}-cargo- diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0f2ea9df3..598f397e2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -34,7 +34,8 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - guest/target/ + ceno_rt/target/ + example/target/ key: tests-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} restore-keys: tests-${{ runner.os }}-cargo- From afe1239c460ff8f77958f67cdc69987340ce455d Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 13 Dec 2024 19:05:07 +0800 Subject: [PATCH 37/44] Inline --- examples-builder/build.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples-builder/build.rs b/examples-builder/build.rs index 7ea9b9628..3a7be2c37 100644 --- a/examples-builder/build.rs +++ b/examples-builder/build.rs @@ -44,10 +44,9 @@ fn build_elfs() { include_bytes!(r"{CARGO_MANIFEST_DIR}/../examples/target/riscv32im-unknown-none-elf/release/examples/{example}");"# ).expect("failed to write vars.rs"); } - let input_path = "../examples/"; + println!("cargo:rerun-if-changed=../examples/"); + println!("cargo:rerun-if-changed=../ceno_rt/"); let elfs_path = "../examples/target/riscv32im-unknown-none-elf/release/examples/"; - - println!("cargo:rerun-if-changed={input_path}"); println!("cargo:rerun-if-changed={elfs_path}"); } From 56daf8bdc993cf164c6423b189bd9581d4966acb Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Mon, 16 Dec 2024 11:43:07 +0800 Subject: [PATCH 38/44] Rename as suggested --- ceno_emul/src/host_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ceno_emul/src/host_utils.rs b/ceno_emul/src/host_utils.rs index 460635f83..43ef7b06b 100644 --- a/ceno_emul/src/host_utils.rs +++ b/ceno_emul/src/host_utils.rs @@ -23,7 +23,7 @@ fn read_message(state: &VMState, offset: WordAddr) -> String { String::from_utf8_lossy( &(out_addr + 1_usize..) - .map(|memory| state.peek_memory(memory)) + .map(|address| state.peek_memory(address)) .flat_map(u32::to_le_bytes) .take(byte_len) .collect::>(), From bd3db0a877af9e0111369badf8a396d61d837f89 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Mon, 16 Dec 2024 11:44:26 +0800 Subject: [PATCH 39/44] Lint --- examples/Cargo.lock | 5 ----- examples/Cargo.toml | 3 --- 2 files changed, 8 deletions(-) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index a04bc9c8d..c0c2418cc 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -3,7 +3,6 @@ version = 4 [[package]] -<<<<<<< HEAD name = "bytecheck" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -187,7 +186,3 @@ name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" -======= -name = "ceno_rt" -version = "0.1.0" ->>>>>>> origin/master diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 6703129b7..6be7ab795 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -11,10 +11,7 @@ version = "0.1.0" [dependencies] ceno_rt = { path = "../ceno_rt" } -<<<<<<< HEAD rkyv = { version = "0.8", default-features = false, features = [ "alloc", "bytecheck", ] } -======= ->>>>>>> origin/master From b794b4d56f3a63ecf99001ec12cf2d25ffcf16be Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Mon, 16 Dec 2024 13:19:31 +0800 Subject: [PATCH 40/44] Update --- .github/workflows/integration.yml | 2 +- Cargo.lock | 122 +++++---------------- ceno_rt/Cargo.lock | 173 ++++++++++++++++++++++++++++++ ceno_rt/ceno_link.x | 3 +- ceno_rt/src/mmio.rs | 53 +++++---- 5 files changed, 239 insertions(+), 114 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 1150da037..cd22cc066 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -47,8 +47,8 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - example/target/ ceno_rt/target/ + example/target/ key: integration-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - uses: dtolnay/rust-toolchain@nightly diff --git a/Cargo.lock b/Cargo.lock index 90a1a0f4d..3bfef12f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,7 +153,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -240,9 +240,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ "shlex", ] @@ -407,12 +407,12 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -497,18 +497,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -525,9 +525,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -1304,7 +1304,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1451,7 +1451,7 @@ dependencies = [ "smallvec", "symbolic-demangle", "tempfile", - "thiserror 2.0.6", + "thiserror 2.0.7", ] [[package]] @@ -1994,11 +1994,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767" dependencies = [ - "thiserror-impl 2.0.6", + "thiserror-impl 2.0.7", ] [[package]] @@ -2014,9 +2014,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" dependencies = [ "proc-macro2", "quote", @@ -2354,22 +2354,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2378,22 +2369,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -2402,46 +2378,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -2454,48 +2412,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/ceno_rt/Cargo.lock b/ceno_rt/Cargo.lock index 0cb45d5c7..8157a3858 100644 --- a/ceno_rt/Cargo.lock +++ b/ceno_rt/Cargo.lock @@ -2,6 +2,179 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "bytecheck" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c8f430744b23b54ad15161fcbc22d82a29b73eacbe425fea23ec822600bc6f" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "rancor", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523363cbe1df49b68215efdf500b103ac3b0fb4836aed6d15689a076eadb8fff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ceno_rt" version = "0.1.0" +dependencies = [ + "rkyv", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "munge" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64142d38c84badf60abf06ff9bd80ad2174306a5b11bd4706535090a30a419df" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb5c1d8184f13f7d0ccbeeca0def2f9a181bce2624302793005f5ca8aa62e5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rancor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" +dependencies = [ + "ptr_meta", +] + +[[package]] +name = "rend" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rkyv" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11a153aec4a6ab60795f8ebe2923c597b16b05bb1504377451e705ef1a45323" +dependencies = [ + "bytecheck", + "hashbrown", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beb382a4d9f53bd5c0be86b10d8179c3f8a14c30bf774ff77096ed6581e35981" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" diff --git a/ceno_rt/ceno_link.x b/ceno_rt/ceno_link.x index 4c2e9e257..956531d41 100644 --- a/ceno_rt/ceno_link.x +++ b/ceno_rt/ceno_link.x @@ -1,7 +1,8 @@ _stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK); _hints_start = ORIGIN(REGION_HINTS); -_hints_end = ORIGIN(REGION_HINTS) + LENGTH(REGION_HINTS); +_hints_length = LENGTH(REGION_HINTS); +_lengths_of_hints_start = ORIGIN(REGION_HINTS); SECTIONS { diff --git a/ceno_rt/src/mmio.rs b/ceno_rt/src/mmio.rs index 1f7bddc44..bca62730e 100644 --- a/ceno_rt/src/mmio.rs +++ b/ceno_rt/src/mmio.rs @@ -4,30 +4,47 @@ use rkyv::{Portable, api::high::HighValidator, bytecheck::CheckBytes, rancor::Fa use core::slice::from_raw_parts; -extern "C" { - /// The address of this variable is the start of the hints ROM. - /// - /// It is defined in the linker script. - static _hints_start: u8; - static _hints_end: u8; +/// The memory region with our hints. +/// +/// Logically, this is a static constant, but the tytpe system doesn't see it that way. +/// (We hope that the optimiser is smart enough to see that it is a constant.) +fn hints_region<'a>() -> &'a [u8] { + extern "C" { + /// The address of this variable is the start of the hints ROM. + /// + /// It is defined in the linker script. The value of this variable is undefined. + static _hints_start: u8; + /// The _address_ of this variable is the length of the hints ROM + /// + /// It is defined in the linker script. The value of this variable is undefined. + static _hints_length: usize; + } + unsafe { + let hints_length = &_hints_length as *const usize as usize; + from_raw_parts(&_hints_start, hints_length) + } } -static mut NEXT_HINT_LEN_AT: *const u8 = &raw const _hints_start; - -pub fn read_slice<'a>() -> &'a [u8] { +/// Get the length of the next hint +fn hint_len() -> usize { + extern "C" { + /// The address of this variable is the start of the slice that holds the length of the hints. + /// + /// It is defined in the linker script. The value of this variable is undefined. + static _lengths_of_hints_start: usize; + } + static mut NEXT_HINT_LEN_AT: *const usize = &raw const _lengths_of_hints_start; unsafe { - let len: u32 = core::ptr::read(NEXT_HINT_LEN_AT as *const u32); - NEXT_HINT_LEN_AT = NEXT_HINT_LEN_AT.add(4); - - let hints_region = { - let total_length = (&raw const _hints_end).offset_from(&_hints_start) as usize; - from_raw_parts(&_hints_start, total_length) - }; - - &hints_region[..len as usize] + let len: usize = core::ptr::read(NEXT_HINT_LEN_AT); + NEXT_HINT_LEN_AT = NEXT_HINT_LEN_AT.add(1); + len } } +pub fn read_slice<'a>() -> &'a [u8] { + &hints_region()[..hint_len()] +} + pub fn read<'a, T>() -> &'a T where T: Portable + for<'c> CheckBytes>, From 279b87ea026efd4188262e59242753dd029451f8 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Mon, 16 Dec 2024 13:19:52 +0800 Subject: [PATCH 41/44] Minimise diff --- .github/workflows/integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index cd22cc066..1150da037 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -47,8 +47,8 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - ceno_rt/target/ example/target/ + ceno_rt/target/ key: integration-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - uses: dtolnay/rust-toolchain@nightly From 2c53a46e7beaa91d3e229efccb274942a0434c8f Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Mon, 16 Dec 2024 13:21:32 +0800 Subject: [PATCH 42/44] More leeway --- ceno_host/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ceno_host/Cargo.toml b/ceno_host/Cargo.toml index ad2b6e044..e589e5854 100644 --- a/ceno_host/Cargo.toml +++ b/ceno_host/Cargo.toml @@ -13,7 +13,7 @@ version.workspace = true anyhow.workspace = true ceno_emul = { path = "../ceno_emul" } itertools.workspace = true -rkyv = { version = "0.8.9", default-features = false, features = ["alloc", "bytecheck"] } +rkyv = { version = "0.8", default-features = false, features = ["alloc", "bytecheck"] } [dev-dependencies] ceno-examples = { path = "../examples-builder" } From 5f2ebe82f15f3a9dd478a38505e660fc5b4e0579 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Mon, 16 Dec 2024 14:55:22 +0800 Subject: [PATCH 43/44] Finalise --- ceno_host/src/lib.rs | 126 +++++++++++++++++++++++++++++++------------ 1 file changed, 91 insertions(+), 35 deletions(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index 49b58f3ee..d8f8baebd 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -1,8 +1,12 @@ -use std::{collections::HashSet, iter::zip, sync::Arc}; +use std::{ + collections::HashSet, + iter::{repeat, zip}, + sync::Arc, +}; use anyhow::Result; use ceno_emul::{IterAddresses, Platform, Program, VMState, host_utils::read_all_messages}; -use itertools::izip; +use itertools::{Itertools, chain}; use rkyv::{ Serialize, api::high::HighSerializer, rancor::Error, ser::allocator::ArenaHandle, to_bytes, util::AlignedVec, @@ -16,11 +20,95 @@ pub const RKYV_ALIGNMENT: usize = { AlignedVec::ALIGNMENT }; +/// A structure for building the hints input to the Ceno emulator. +/// +/// Use the `write` method to add a hint to the input. +/// When you are done, call `into` to convert to a `Vec` to pass to the emulator. +/// +/// Our guest programs have two requirements on the format: +/// 1. The start of the hints buffer consists of a sequence of `usize` values, each representing the +/// length of the next hint (from the start of the whole buffer). +/// 2. hints[..current_hint_len] can deserialise into the expected type via rkyv. +/// +/// Note how we overlap the two areas, and don't specify starts for our hints. That's a simplification +/// and performance improvement we can make because of how rkyv works: you can add arbitrary padding to +/// the left of a serialised buffer, and it will still work. #[derive(Default)] pub struct CenoStdin { pub items: Vec, } +#[derive(Debug, Default, Clone)] +pub struct Item { + pub data: Vec, + pub end_of_data: usize, +} + +impl From<&AlignedVec> for Item { + fn from(data: &AlignedVec) -> Self { + let mut data = data.to_vec(); + let end_of_data = data.len(); + data.resize(data.len().next_multiple_of(RKYV_ALIGNMENT), 0); + Item { data, end_of_data } + } +} + +impl From> for Item { + fn from(data: Vec) -> Self { + let data: Vec = data.into_iter().flat_map(u32::to_le_bytes).collect(); + Item { + end_of_data: data.len(), + data, + } + } +} + +#[derive(Debug, Default, Clone)] +pub struct Items { + pub data: Vec, + pub ends: Vec, +} + +impl Items { + pub fn total_length(&self) -> usize { + self.data.len() + } + pub fn append(&mut self, item: Item) { + let end = self.total_length() + item.end_of_data; + self.data.extend_from_slice(&item.data); + self.ends.push(end); + } + + pub fn shift(&mut self, n: usize) { + for end in &mut self.ends { + *end += n; + } + } + + pub fn finalise(mut self) -> Vec { + let start_of_data = (size_of::() * self.ends.len()).next_multiple_of(RKYV_ALIGNMENT); + self.shift(start_of_data); + let lengths = self.ends.iter().map(|&end| end as u32); + let padded_lengths = + chain!(lengths.flat_map(u32::to_le_bytes), repeat(0_u8)).take(start_of_data); + chain!(padded_lengths, self.data.clone()).collect() + } +} + +impl From<&CenoStdin> for Vec { + fn from(stdin: &CenoStdin) -> Vec { + let mut items = Items::default(); + for item in &stdin.items { + items.append(Item::from(item)); + } + let data = items.finalise(); + data.into_iter() + .tuples() + .map(|(a, b, c, d)| u32::from_le_bytes([a, b, c, d])) + .collect() + } +} + impl CenoStdin { pub fn write_slice(&mut self, bytes: AlignedVec) { self.items.push(bytes); @@ -32,38 +120,6 @@ impl CenoStdin { ) -> Result<(), Error> { to_bytes::(item).map(|bytes| self.write_slice(bytes)) } - - pub fn finalise(&self) -> Vec { - let initial_offset = (size_of::() * self.items.len()).next_multiple_of(RKYV_ALIGNMENT); - let offsets: Vec = self - .items - .iter() - .scan(initial_offset, |acc, bytes| { - let output = (*acc + bytes.len()) as u32; - *acc += bytes.len().next_multiple_of(RKYV_ALIGNMENT); - Some(output) - }) - .collect(); - let offsets_u8: Vec = offsets.iter().copied().flat_map(u32::to_le_bytes).collect(); - let mut buf: AlignedVec = AlignedVec::new(); - buf.extend_from_slice(&offsets_u8); - buf.extend_from_slice(&vec![ - 0; - buf.len().next_multiple_of(RKYV_ALIGNMENT) - buf.len() - ]); - for (offset, item) in izip!(offsets, &self.items) { - buf.extend_from_slice(item); - buf.resize(buf.len().next_multiple_of(RKYV_ALIGNMENT), 0); - assert_eq!( - buf.len(), - (offset as usize).next_multiple_of(RKYV_ALIGNMENT) - ); - } - let (prefix, hints, postfix): (_, &[u32], _) = unsafe { buf.align_to() }; - assert_eq!(prefix, &[]); - assert_eq!(postfix, &[]); - hints.to_vec() - } } pub fn run(platform: Platform, elf: &[u8], hints: &CenoStdin) -> Vec { @@ -73,7 +129,7 @@ pub fn run(platform: Platform, elf: &[u8], hints: &CenoStdin) -> Vec { ..platform }; - let hints: Vec = hints.finalise(); + let hints: Vec = hints.into(); let hints_range = platform.hints.clone(); let mut state = VMState::new(platform, Arc::new(program)); From 7dff29eb2aad68d6901626e6352163455c764c38 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Mon, 16 Dec 2024 14:58:02 +0800 Subject: [PATCH 44/44] Inline --- ceno_host/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index d8f8baebd..5e309de74 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -101,8 +101,9 @@ impl From<&CenoStdin> for Vec { for item in &stdin.items { items.append(Item::from(item)); } - let data = items.finalise(); - data.into_iter() + items + .finalise() + .into_iter() .tuples() .map(|(a, b, c, d)| u32::from_le_bytes([a, b, c, d])) .collect()