diff --git a/Cargo.lock b/Cargo.lock index f1406202e..0b110aa22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "either" version = "1.9.0" @@ -35,8 +41,8 @@ name = "kona-common" version = "0.0.1" dependencies = [ "anyhow", + "cfg-if", "good_memory_allocator", - "num", ] [[package]] @@ -49,69 +55,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "num" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" -dependencies = [ - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - [[package]] name = "scopeguard" version = "1.2.0" diff --git a/README.md b/README.md index a008c67c9..e8bff1c9c 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,17 @@

- A suite of libraries and build pipelines for developing verifiable Rust programs targeting Fault Proof VMs. + A verifiable implementation of the [Optimism][op-stack] rollup state transition.

- Ci + CI License + + Book + OP Stack

@@ -25,26 +28,19 @@ ## What's Kona? -Kona is a suite of libraries and build pipelines for developing verifiable Rust programs targeting Fault Proof VMs. Currently, Kona seeks to support the following targets: -* [`cannon`][cannon] & [`cannon-rs`][cannon-rs]: A `MIPS32rel1` based Fault Proof VM. -* [`asterisc`][asterisc]: A `RISC-V` based Fault Proof VM. - -This repository also contains an implementation of the [`op-program` specification][fpp-specs] in Rust, which is used to validate a claim about the state of an [OP Stack rollup][op-stack] on L1 Ethereum. +Kona is a [fault proof program] designed to execute a rollup state transition and ultimately verify an [L2 output root][g-output-root] from +L1 inputs, derived through the rollup's [derivation pipeline][g-derivation-pipeline]. ## Overview -*todo* +*TODO - overview after mockup* ``` crates -├── `common-client`: A suite of utilities for developing `client` programs to be ran on top of Fault Proof VMs. -└── `common-host`: A suite of utilities for developing `host` programs. +├── `common`: A suite of utilities for developing `client` programs to be ran on top of Fault Proof VMs. +└── `placeholder`: Placeholder ``` -## Credits - -`kona` is inspired by the work of several other teams, namely [OP Labs][op-labs] and other contributors' work on the [`op-program`][op-program] and [BadBoiLabs][bad-boi-labs]. - ## Book The [book][book] contains a more in-depth overview of the project, tutorials for getting started with building your own programs, and a reference for the libraries and tools provided by Kona. @@ -53,10 +49,15 @@ The [book][book] contains a more in-depth overview of the project, tutorials for *TODO - write `CONTRIBUTING.md`* +## Credits + +`kona` is inspired by the work of several teams, namely [OP Labs][op-labs] and other contributors' work on the [`op-program`][op-program] and [BadBoiLabs][bad-boi-labs]'s work on [Cannon-rs][badboi-cannon-rs]. + [op-stack]: https://github.com/ethereum-optimism/optimism [op-program]: https://github.com/ethereum-optimism/optimism/tree/develop/op-program [cannon]: https://github.com/ethereum-optimism/optimism/tree/develop/cannon [cannon-rs]: https://github.com/anton-rs/cannon-rs +[badboi-cannon-rs]: https://github.com/BadBoiLabs/cannon-rs [asterisc]: https://github.com/protolambda/asterisc [fpp-specs]: https://github.com/ethereum-optimism/optimism/blob/develop/specs/fault-proof.md#fault-proof-program @@ -64,3 +65,7 @@ The [book][book] contains a more in-depth overview of the project, tutorials for [op-labs]: https://github.com/ethereum-optimism [bad-boi-labs]: https://github.com/BadBoiLabs + +[g-output-root]: https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#l2-output-root +[g-derivation-pipeline]: https://github.com/ethereum-optimism/optimism/blob/develop/specs/derivation.md#l2-chain-derivation-pipeline +[g-fault-proof-vm]: https://github.com/ethereum-optimism/optimism/blob/develop/specs/fault-proof.md#fault-proof-vm diff --git a/bin/client/.gitkeep b/bin/client/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/bin/server/.gitkeep b/bin/server/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/fpp-dev/targets.md b/book/src/fpp-dev/targets.md index 31e6b0c70..973fb34c2 100644 --- a/book/src/fpp-dev/targets.md +++ b/book/src/fpp-dev/targets.md @@ -5,9 +5,32 @@ for each FPVM target: | Target | Build Pipeline | IO | malloc | Program Stages | |------------------------|----------------|----|--------|----------------| -| `cannon` & `cannon-rs` | ❌ | ❌ | ❌ | ❌ | -| `asterisc` | ❌ | ❌ | ❌ | ❌ | +| `cannon` & `cannon-rs` | ✅ | ✅ | ✅ | ❌ | +| `asterisc` | ❌ | ✅ | ✅ | ❌ | If there is a feature that you would like to see supported, please [open an issue][new-issue] or [consider contributing][contributing]! +## Asterisc (RISC-V) + +Asterisc is based off of the `rv64gc` target architecture, which defines the following extensions: +- `RV32I` support - 32 bit base instruction set + - `FENCE`, `ECALL`, `EBREAK` are hardwired to implement a minimal subset of systemcalls of the linux kernel + - Work in progress. All syscalls used by the Golang `risc64` runtime. +- `RV64I` support +- `RV64C`: Compressed instructions +- `RV32M`+`RV64M`: Multiplication support +- `RV32A`+`RV64A`: Atomics support +- `RV{32,64}{D,F,Q}`: no-op: No floating points support (since no IEEE754 determinism with rounding modes etc., nor worth the complexity) +- `Zifencei`: `FENCE.I` no-op: No need for `FENCE.I` +- `Zicsr`: no-op: some support for Control-and-status registers may come later though. +- `Ztso`: no-op: no need for Total Store Ordering +- other: revert with error code on unrecognized instructions + +`asterisc` supports a plethora of syscalls, documented [in the repository][asterisc-syscalls]. `kona` offers an interface for +programs to directly invoke several syscalls: +1. `EXIT` - Terminate the process with the provided exit code. +1. `WRITE` - Write the passed buffer to the passed file descriptor. +1. `READ` - Read the specified number of bytes from the passed file descriptor. + +[asterisc-syscalls]: https://github.com/protolambda/asterisc {{#include ../links.md}} diff --git a/book/src/glossary.md b/book/src/glossary.md index 80ef0640b..8c1fe85dd 100644 --- a/book/src/glossary.md +++ b/book/src/glossary.md @@ -3,7 +3,7 @@ *This document contains definitions for terms used throughout the Kona book.* #### Fault Proof VM -A `Fault Proof VM` is a virtual machine, commonly supporting a modified subset of an existing reduced instruction set architecture, +A `Fault Proof VM` is a virtual machine, commonly supporting a subset of the Linux kernel's syscalls and a modified subset of an existing reduced instruction set architecture, that is designed to execute verifiable programs. Full specification for the `cannon` & `cannon-rs` FPVMs, as an example, is available in the [Optimism Monorepo][cannon-specs]. diff --git a/build/README.md b/build/README.md index 8dc77abde..8b18a1c38 100644 --- a/build/README.md +++ b/build/README.md @@ -10,6 +10,8 @@ To build the images, run `make` in the root of this directory. ### Compiling Programs +**cannon** + ``` docker run \ --rm \ @@ -19,4 +21,10 @@ docker run \ cannon-pipeline:latest cargo build --release -Zbuild-std ``` +**asterisc** +``` +RUSTFLAGS="-Clink-arg=-e_start -C target-feature=-c" \ + cargo build --target riscv64gc-unknown-none-elf --release +``` + [cross]: https://github.com/cross-rs/cross diff --git a/build/asterisc/.gitkeep b/build/asterisc/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/build/Makefile b/build/justfile similarity index 66% rename from build/Makefile rename to build/justfile index f54ba7f3f..c65ba6af1 100644 --- a/build/Makefile +++ b/build/justfile @@ -1,5 +1,3 @@ -all: cannon - -.PHONY: cannon +# Build the `cannon` program builder image cannon: docker build -t cannon-pipeline:latest -f cannon/cannon.dockerfile ./cannon diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 73ed05d93..a53fc800b 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kona-common" -description = "Common traits and utilities for Kona" +description = "Common traits and system interfaces for developing client programs on top of Fault Proof VMs." version = { workspace = true } edition = { workspace = true } authors = { workspace = true } @@ -13,5 +13,5 @@ homepage = { workspace = true } anyhow.workspace = true # external -num = { version = "0.4.1", default-features = false } good_memory_allocator = "0.1.7" +cfg-if = "1.0.0" diff --git a/crates/common/README.md b/crates/common/README.md index 26b6055b9..3a141c4a4 100644 --- a/crates/common/README.md +++ b/crates/common/README.md @@ -1,5 +1,5 @@ -# `kona-common` +# `kona-client` -A suite of utilities for developing `host` programs and verifiable `client` executables. +A suite of utilities for developing verifiable `client` executables that may run on top of FPVM targets. *TODO* diff --git a/crates/common/src/asterisc/io.rs b/crates/common/src/asterisc/io.rs new file mode 100644 index 000000000..df6a1e8dc --- /dev/null +++ b/crates/common/src/asterisc/io.rs @@ -0,0 +1,54 @@ +use crate::{asterisc::syscall, traits::BasicKernelInterface, types::RegisterSize}; +use anyhow::Result; + +/// Concrete implementation of the [`KernelIO`] trait for the `riscv64` target architecture. +pub struct AsteriscIO; + +/// Relevant system call numbers for the `riscv64` target architecture. +/// +/// See https://jborza.com/post/2021-05-11-riscv-linux-syscalls/ +/// +/// **Note**: This is not an exhaustive list of system calls available to the `client` program, +/// only the ones necessary for the [BasicKernelInterface] trait implementation. If an extension trait for +/// the [BasicKernelInterface] trait is created for the `asterisc` kernel, this list should be extended +/// accordingly. +#[repr(u32)] +pub enum SyscallNumber { + /// Sets the Exited and ExitCode states to true and $a0 respectively. + Exit = 93, + /// Similar behavior as Linux with support for unaligned reads. + Read = 63, + /// Similar behavior as Linux with support for unaligned writes. + Write = 64, +} + +impl BasicKernelInterface for AsteriscIO { + fn write(fd: Self::FileDescriptor, buf: &[u8]) -> Result { + unsafe { + Ok(syscall::syscall3( + SyscallNumber::Write as usize, + fd as usize, + buf.as_ptr() as usize, + buf.len() as usize, + ) as RegisterSize) + } + } + + fn read(fd: Self::FileDescriptor, buf: &mut [u8]) -> Result { + unsafe { + Ok(syscall::syscall3( + SyscallNumber::Read as usize, + fd as usize, + buf.as_ptr() as usize, + buf.len() as usize, + ) as RegisterSize) + } + } + + fn exit(code: RegisterSize) -> ! { + unsafe { + syscall::syscall1(SyscallNumber::Exit as usize, code as usize); + panic!() + } + } +} diff --git a/crates/common/src/asterisc/mod.rs b/crates/common/src/asterisc/mod.rs new file mode 100644 index 000000000..05fcc1a3e --- /dev/null +++ b/crates/common/src/asterisc/mod.rs @@ -0,0 +1,4 @@ +//! TODO + +pub mod io; +mod syscall; diff --git a/crates/common/src/asterisc/syscall.rs b/crates/common/src/asterisc/syscall.rs new file mode 100644 index 000000000..c0a23cbe6 --- /dev/null +++ b/crates/common/src/asterisc/syscall.rs @@ -0,0 +1,44 @@ +//! Unsafe system call interface for the `riscv64` target architecture. +//! +//! List of RISC-V system calls: https://jborza.com/post/2021-05-11-riscv-linux-syscalls/ +//! +//! **Registers used for system calls** +//! | Register Number | Description | +//! |=================|====================| +//! | %a0 | arg1, return value | +//! | %a1 | arg2 | +//! | %a2 | arg3 | +//! | %a3 | arg4 | +//! | %a4 | arg5 | +//! | %a5 | arg6 | +//! | %a7 | syscall number | + +use core::arch::asm; + +/// Issues a raw system call with 1 argument. (e.g. exit) +#[inline] +pub unsafe fn syscall1(syscall_number: usize, arg1: usize) -> usize { + let mut ret: usize; + asm!( + "ecall", + in("a7") syscall_number, + inlateout("a0") arg1 => ret, + options(nostack, preserves_flags) + ); + ret +} + +/// Issues a raw system call with 3 arguments. (e.g. read, write) +#[inline] +pub unsafe fn syscall3(syscall_number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { + let mut ret: usize; + asm!( + "ecall", + in("a7") syscall_number, + inlateout("a0") arg1 => ret, + in("a1") arg2, + in("a2") arg3, + options(nostack, preserves_flags) + ); + ret +} diff --git a/crates/common/src/cannon/io.rs b/crates/common/src/cannon/io.rs new file mode 100644 index 000000000..f539e657b --- /dev/null +++ b/crates/common/src/cannon/io.rs @@ -0,0 +1,59 @@ +use crate::{cannon::syscall, traits::BasicKernelInterface, types::RegisterSize}; +use anyhow::{anyhow, Result}; + +/// Concrete implementation of the [BasicKernelInterface] trait for the `MIPS32rel1` target architecture. Exposes a safe +/// interface for performing IO operations within the FPVM kernel. +pub struct CannonIO; + +/// Relevant system call numbers for the `MIPS32rel1` target architecture. +/// +/// See [Cannon System Call Specification](https://github.com/ethereum-optimism/optimism/blob/develop/specs/cannon-fault-proof-vm.md#syscalls) +/// +/// **Note**: This is not an exhaustive list of system calls available to the `client` program, +/// only the ones necessary for the [BasicKernelInterface] trait implementation. If an extension trait for +/// the [BasicKernelInterface] trait is created for the `Cannon` kernel, this list should be extended +/// accordingly. +#[repr(u32)] +pub enum SyscallNumber { + /// Sets the Exited and ExitCode states to true and $a0 respectively. + Exit = 4246, + /// Similar behavior as Linux/MIPS with support for unaligned reads. + Read = 4003, + /// Similar behavior as Linux/MIPS with support for unaligned writes. + Write = 4004, +} + +impl BasicKernelInterface for CannonIO { + type FileDescriptor = crate::io::FileDescriptor; + + fn write(fd: Self::FileDescriptor, buf: &[u8]) -> Result { + unsafe { + syscall::syscall3( + SyscallNumber::Write as u32, + fd as u32, + buf.as_ptr() as u32, + buf.len() as u32, + ) + .map_err(|e| anyhow!("Syscall Error: {e}")) + } + } + + fn read(fd: Self::FileDescriptor, buf: &mut [u8]) -> Result { + unsafe { + syscall::syscall3( + SyscallNumber::Read as u32, + fd as u32, + buf.as_ptr() as u32, + buf.len() as u32, + ) + .map_err(|e| anyhow!("Syscall Error: {e}")) + } + } + + fn exit(code: RegisterSize) -> ! { + unsafe { + syscall::syscall1(SyscallNumber::Exit as RegisterSize, code); + panic!() + } + } +} diff --git a/crates/common/src/cannon/mod.rs b/crates/common/src/cannon/mod.rs new file mode 100644 index 000000000..723055e77 --- /dev/null +++ b/crates/common/src/cannon/mod.rs @@ -0,0 +1,4 @@ +//! TODO + +pub(crate) mod io; +mod syscall; diff --git a/crates/common/src/cannon/syscall.rs b/crates/common/src/cannon/syscall.rs new file mode 100644 index 000000000..95ccc7116 --- /dev/null +++ b/crates/common/src/cannon/syscall.rs @@ -0,0 +1,106 @@ +//! Taken from the syscalls crate https://github.com/jasonwhite/syscalls +//! +//! MIPS has the following registers: +//! +//! | Symbolic Name | Number | Usage | +//! | ============= | =============== | ============================== | +//! | zero | 0 | Constant 0. | +//! | at | 1 | Reserved for the assembler. | +//! | v0 - v1 | 2 - 3 | Result Registers. | +//! | a0 - a3 | 4 - 7 | Argument Registers 1 ·· · 4. | +//! | t0 - t9 | 8 - 15, 24 - 25 | Temporary Registers 0 · · · 9. | +//! | s0 - s7 | 16 - 23 | Saved Registers 0 ·· · 7. | +//! | k0 - k1 | 26 - 27 | Kernel Registers 0 ·· · 1. | +//! | gp | 28 | Global Data Pointer. | +//! | sp | 29 | Stack Pointer. | +//! | fp | 30 | Frame Pointer. | +//! | ra | 31 | Return Address. | +//! +//! The following registers are used for args 1-6: +//! +//! arg1: %a0 ($4) +//! arg2: %a1 ($5) +//! arg3: %a2 ($6) +//! arg4: %a3 ($7) +//! arg5: (Passed via user stack) +//! arg6: (Passed via user stack) +//! arg7: (Passed via user stack) +//! +//! %v0 is the syscall number. +//! %v0 is the return value. +//! %v1 is the error code +//! %a3 is a boolean indicating that an error occurred. +//! +//! +//! All temporary registers are clobbered (8-15, 24-25). + +use core::arch::asm; + +/// Issues a raw system call with 1 argument. (e.g. exit) +#[inline] +pub unsafe fn syscall1(n: u32, arg1: u32) -> u32 { + let mut err: u32; + let mut ret: u32; + asm!( + "syscall", + inlateout("$2") n => ret, + lateout("$7") err, + in("$4") arg1, + // Clobber all temporary registers + lateout("$8") _, + lateout("$9") _, + lateout("$10") _, + lateout("$11") _, + lateout("$12") _, + lateout("$13") _, + lateout("$14") _, + lateout("$15") _, + lateout("$24") _, + lateout("$25") _, + options(nostack, preserves_flags) + ); + + (err == 0) + .then_some(ret) + .unwrap_or_else(|| ret.wrapping_neg()) +} + +/// Issues a raw system call with 3 arguments. (e.g. read, write) +#[inline] +pub unsafe fn syscall3(n: u32, arg1: u32, arg2: u32, arg3: u32) -> Result { + let mut err: u32; + let mut ret: u32; + asm!( + "syscall", + inlateout("$2") n => ret, + lateout("$7") err, + in("$4") arg1, + in("$5") arg2, + in("$6") arg3, + // Clobber all temporary registers + lateout("$8") _, + lateout("$9") _, + lateout("$10") _, + lateout("$11") _, + lateout("$12") _, + lateout("$13") _, + lateout("$14") _, + lateout("$15") _, + lateout("$24") _, + lateout("$25") _, + options(nostack, preserves_flags) + ); + + let value = (err == 0) + .then_some(ret) + .unwrap_or_else(|| ret.wrapping_neg()); + + (value <= -4096isize as u32) + .then_some(value) + .ok_or_else(|| { + // Truncation of the error value is guaranteed to never occur due to + // the above check. This is the same check that musl uses: + // https://git.musl-libc.org/cgit/musl/tree/src/internal/syscall_ret.c?h=v1.1.15 + -(value as i32) + }) +} diff --git a/crates/common/src/io.rs b/crates/common/src/io.rs new file mode 100644 index 000000000..af695de63 --- /dev/null +++ b/crates/common/src/io.rs @@ -0,0 +1,78 @@ +//! This module contains the [ClientIO] struct, which is used to perform various IO operations +//! inside of the FPVM kernel within a `client` program. + +use crate::{traits::BasicKernelInterface, types::RegisterSize}; +use anyhow::Result; +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(target_arch = "mips")] { + #[doc = "Concrete implementation of the [`BasicKernelInterface`] trait for the `MIPS32rel1` target architecture."] + pub type ClientIO = crate::cannon::io::CannonIO; + } else if #[cfg(target_arch = "riscv64")] { + #[doc = "Concrete implementation of the [`BasicKernelInterface`] trait for the `riscv64` target architecture."] + pub type ClientIO = crate::asterisc::io::AsteriscIO; + } else { + #[doc = "Concrete implementation of the [`BasicKernelInterface`] trait for the `native` target architecture."] + pub type ClientIO = native_io::NativeIO; + } +} + +/// File descriptors available to the `client` within the FPVM kernel. +#[repr(u8)] +#[derive(Debug, Clone, Copy)] +pub enum FileDescriptor { + /// Read-only standard input stream. + StdIn = 0, + /// Write-only standaard output stream. + StdOut = 1, + /// Write-only standard error stream. + StdErr = 2, + /// Read-only. Used to read the status of pre-image hinting. + HintRead = 3, + /// Write-only. Used to provide pre-image hints + HintWrite = 4, + /// Read-only. Used to read pre-images. + PreimageRead = 5, + /// Write-only. Used to request pre-images. + PreimageWrite = 6, +} + +#[cfg(not(any(target_arch = "mips", target_arch = "riscv64")))] +mod native_io { + extern crate std; + + use super::{BasicKernelInterface, FileDescriptor, RegisterSize, Result}; + use anyhow::anyhow; + use std::{ + fs::File, + io::{Read, Write}, + os::fd::FromRawFd, + }; + + /// Mock IO implementation for native tests. + #[derive(Debug)] + pub struct NativeIO; + + impl BasicKernelInterface for NativeIO { + fn write(fd: FileDescriptor, buf: &[u8]) -> Result { + let mut file = unsafe { File::from_raw_fd(fd as i32) }; + file.write_all(buf) + .map_err(|e| anyhow!("Error writing to buffer to file descriptor: {e}"))?; + std::mem::forget(file); // forget the file descriptor so that the `Drop` impl doesn't close it. + Ok(0) + } + + fn read(fd: FileDescriptor, buf: &mut [u8]) -> Result { + let mut file = unsafe { File::from_raw_fd(fd as i32) }; + file.read(buf) + .map_err(|e| anyhow!("Error reading from file descriptor: {e}"))?; + std::mem::forget(file); // forget the file descriptor so that the `Drop` impl doesn't close it. + Ok(0) + } + + fn exit(code: RegisterSize) -> ! { + std::process::exit(code as i32) + } + } +} diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index d1c98b58a..a1afae8b8 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -7,7 +7,17 @@ )] #![deny(unused_must_use, rust_2018_idioms)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -#![cfg_attr(not(test), no_std)] +#![no_std] -pub mod malloc; +pub mod io; pub mod traits; +pub mod types; + +#[cfg(any(target_arch = "mips", target_arch = "riscv64"))] +pub mod malloc; + +#[cfg(target_arch = "mips")] +pub(crate) mod cannon; + +#[cfg(target_arch = "riscv64")] +pub(crate) mod asterisc; diff --git a/crates/common/src/malloc.rs b/crates/common/src/malloc.rs index 0d7e57d1e..b5c012df6 100644 --- a/crates/common/src/malloc.rs +++ b/crates/common/src/malloc.rs @@ -3,16 +3,9 @@ //! `dlmalloc` algorithm, which is a well-known and widely used allocator software such //! as OS Kernels. -#[cfg(not(test))] use good_memory_allocator::SpinLockedAllocator; -/// The global allocator for the program in the `test` profile uses the standard allocator. -#[cfg(test)] -#[global_allocator] -static ALLOCATOR: std::alloc::System = std::alloc::System; - /// The global allocator for the program in other profiles uses the [SpinLockedAllocator]. -#[cfg(not(test))] #[global_allocator] static ALLOCATOR: SpinLockedAllocator = SpinLockedAllocator::empty(); @@ -26,15 +19,16 @@ static ALLOCATOR: SpinLockedAllocator = SpinLockedAllocator::empty(); /// * The provided memory region must be valid, non-null, and not used by anything else. /// * After aligning the start and end addresses, the size of the heap must be > 0, or the function /// will panic. -#[cfg_attr(test, allow(unused_variables))] pub unsafe fn init_allocator(heap_start_addr: usize, heap_size: usize) { - #[cfg(not(test))] ALLOCATOR.init(heap_start_addr, heap_size) } -/// Initialize heap memory for the `client` program with +/// Initialize heap memory for the `client` program with the given size. +/// +/// # Safety +/// See [init_allocator] safety comment. #[macro_export] -macro_rules! init_heap { +macro_rules! alloc_heap { ($size:expr) => {{ use kona_common::malloc::init_allocator; diff --git a/crates/common/src/traits/basic.rs b/crates/common/src/traits/basic.rs new file mode 100644 index 000000000..adf14d5e3 --- /dev/null +++ b/crates/common/src/traits/basic.rs @@ -0,0 +1,27 @@ +//! Defines the [BasicKernelInterface] trait, which describes the functionality of several system calls inside of +//! the FPVM kernel. + +use crate::{io::FileDescriptor, types::RegisterSize}; +use anyhow::Result; + +/// The [BasicKernelInterface] trait describes the functionality of several core system calls inside of +/// the FPVM kernel. Commonly, FPVMs delegate IO operations to custom file descriptors in the `client` program. It is +/// a safe wrapper around the raw system calls available to the `client` program. +/// +/// +/// The `RS` type parameter is the size of the registers in the VM. On MIPS32 for example, this would be 32, and on +/// RISC-V/64 this would be 64. +/// +/// In cases where the set of system calls defined in this trait need to be extended, an additional trait should be +/// created that extends this trait. +pub trait BasicKernelInterface { + /// Write the given buffer to the given file descriptor. + fn write(fd: FileDescriptor, buf: &[u8]) -> Result; + + /// Read from the given file descriptor into the passed buffer. + fn read(fd: FileDescriptor, buf: &mut [u8]) -> Result; + + /// Exit the process with the given exit code. The implementation of this function + /// should always panic after invoking the `EXIT` syscall. + fn exit(code: RegisterSize) -> !; +} diff --git a/crates/common/src/traits/mod.rs b/crates/common/src/traits/mod.rs index 5d479409d..16f8d5100 100644 --- a/crates/common/src/traits/mod.rs +++ b/crates/common/src/traits/mod.rs @@ -6,5 +6,5 @@ //! without needing to know the underlying implementation, which allows the same `client` //! program to be compiled and ran on different target FPVM architectures. -mod syscall; -pub use syscall::KernelIO; +mod basic; +pub use basic::BasicKernelInterface; diff --git a/crates/common/src/traits/syscall.rs b/crates/common/src/traits/syscall.rs deleted file mode 100644 index 9bab6cccc..000000000 --- a/crates/common/src/traits/syscall.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Defines the [KernelIO] trait, which describes the functionality of several -//! system calls inside of the FPVM kernel. This trait is to be implemented by the -//! `client` program, and then used by the `kernel` to perform IO operations. - -use anyhow::Result; -use num::Unsigned; - -/// The [KernelIO] trait describes the functionality of several system calls inside of -/// the FPVM kernel. Commonly, FPVMs delegate IO operations to custom file descriptors in -/// the `client` program. -/// -/// -/// The `RS` type parameter is the size of the registers in the VM. On MIPS32 for example, -/// this would be 32, and on RISC-V/64 this would be 64. -/// -/// In cases where the set of system calls defined in this trait need to be extended, an -/// additional trait should be created that extends this trait. -pub trait KernelIO { - /// Associated type for the file descriptors available. - type FileDescriptor; - - /// Write the given buffer to the given file descriptor. - fn write(fd: Self::FileDescriptor, buf: &[u8]) -> Result; - - /// Read from the given file descriptor into the passed buffer. - fn read(fd: Self::FileDescriptor, buf: &mut [u8]) -> Result; - - /// Exit the process with the given exit code. The implementation of this function - /// should always panic after invoking the `EXIT` syscall. - fn exit(code: RS) -> !; -} diff --git a/crates/common/src/types.rs b/crates/common/src/types.rs new file mode 100644 index 000000000..9e8ad45bc --- /dev/null +++ b/crates/common/src/types.rs @@ -0,0 +1,16 @@ +//! Constants + +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(target_arch = "mips")] { + /// The size of the `mips32` target architecture's registers. + pub type RegisterSize = u32; + } else if #[cfg(target_arch = "riscv64")] { + /// The size of the `riscv64` target architecture's registers. + pub type RegisterSize = u64; + } else { + /// The size of the native target architecture's registers. + pub type RegisterSize = usize; + } +} diff --git a/justfile b/justfile new file mode 100644 index 000000000..992b51882 --- /dev/null +++ b/justfile @@ -0,0 +1,3 @@ +# Lint the workspace +lint: + cargo +nightly fmt --all && cargo +nightly clippy --all --all-features --all-targets -- -D warnings