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.
-
+
+
+
+
@@ -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