### Starting OpenOCD Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md Command to start the OpenOCD server using the specified configuration file. This allows GDB to connect to the target via the remote bitbang interface. ```bash openocd -f spike.cfg ``` -------------------------------- ### Build RISC-V Spike Simulator with Mojo-V (Bash) Source: https://github.com/toddmaustin/mojo-v/blob/main/README.md This section outlines the steps to build the RISC-V Spike simulator with Mojo-V extensions. It requires installing several dependencies and configuring the build process. The `--prefix` option specifies the installation directory. ```bash sudo apt-get install device-tree-compiler libboost-regex-dev libboost-system-dev cd riscv-isa-sim mkdir build cd build ../configure --prefix=$RISCV make ``` -------------------------------- ### Build Spike RISC-V Simulator (OpenBSD) Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md Instructions for building the Spike RISC-V ISA Simulator on OpenBSD. This process requires specific package installations and environment variable configurations before proceeding with the build. ```bash pkg_add bash gmake dtc exec bash export CC=cc; export CXX=c++ mkdir build cd build ../configure --prefix=$RISCV gmake [doas] make install ``` -------------------------------- ### Compile and Run a C Program with Spike Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md Demonstrates how to compile a simple C program for RISC-V and then simulate its execution using Spike and the riscv-pk proxy kernel. Requires Spike, riscv-gnu-toolchain, and riscv-pk to be installed. ```bash riscv64-unknown-elf-gcc -o hello hello.c spike pk hello ``` -------------------------------- ### GDB Session for Remote Debugging Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md Commands to start a GDB session and connect to the Spike simulator running with OpenOCD. It includes examples of setting breakpoints, printing variables, and continuing execution. ```gdb riscv64-unknown-elf-gdb rot13-64 target remote localhost:3333 print wait print wait=0 print text b done c print wait print text ``` -------------------------------- ### Build Spike RISC-V Simulator (Debian/Ubuntu) Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md Steps to build the Spike RISC-V ISA Simulator on Debian/Ubuntu systems. It involves installing dependencies, configuring the build, and compiling the simulator. Assumes RISCV environment variable is set. ```bash apt-get install device-tree-compiler libboost-regex-dev libboost-system-dev mkdir build cd build ../configure --prefix=$RISCV make [sudo] make install ``` -------------------------------- ### Clone Mojo-V Repository (Bash) Source: https://github.com/toddmaustin/mojo-v/blob/main/README.md This command clones the Mojo-V repository from GitHub. It requires Git to be installed on your system. After cloning, navigate into the repository directory. ```bash git clone https://github.com/toddmaustin/mojo-v.git cd mojo-v ``` -------------------------------- ### Add New Instruction to Spike Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md Guides on how to add a new custom instruction to the Spike RISC-V simulator. This involves defining the instruction's behavior in a header file and updating the opcode definitions. ```bash cd ../riscv-opcodes vi opcodes // add a line for the new instruction make install ``` -------------------------------- ### CSR Configuration API for Mojo-V Secret Computation (C) Source: https://context7.com/toddmaustin/mojo-v/llms.txt This C code configures the Mojo-V secret computation mode using the `mprivregcfg` CSR. It provides functions to read and write CSR values, enabling or disabling secret registers and selecting encryption formats. The example demonstrates checking CSR fields and setting the mode. ```c #define CSR_MPRIVREGCFG 0x0a0 // Read the mprivregcfg CSR value static inline uint64_t read_mprivregcfg(void) { uint64_t value; __asm__ volatile ("csrr %0, %1" : "=r"(value) : "i"(CSR_MPRIVREGCFG)); return value; } // Write to the mprivregcfg CSR static inline void write_mprivregcfg(uint64_t value) { __asm__ volatile ("csrw %0, %1" :: "i"(CSR_MPRIVREGCFG), "rK"(value)); } // Usage example int main(void) { uint64_t val = read_mprivregcfg(); // Check fields: mojov_en (bit 0), key_valid (bit 1), format_sel (bits 2-3), mojov_ver (bits 4-11) printf("mojov_en: %s, format: %s, version: %u\n", (val & 0x01) ? "enabled" : "disabled", ((val >> 2) & 0x03) == 2 ? "proof-carrying" : (((val >> 2) & 0x03) == 1 ? "strong" : "fast"), (val >> 4) & 0xff); // Enable secret computation mode write_mprivregcfg(1); // ... perform secret computations ... // Disable and clear secret registers write_mprivregcfg(0); return 0; } ``` -------------------------------- ### Build and Run Mojo-V Benchmark Tests (Bash) Source: https://github.com/toddmaustin/mojo-v/blob/main/README.md These commands demonstrate how to build and run the Mojo-V Bringup-Bench benchmark tests. It involves building a device driver, configuring the compiler path in a Makefile, and then executing the tests. Individual benchmarks can also be built and tested separately. ```bash cd bringup-bench/target make cd .. # go to the top-level bringup-bench directory make mojov-tests # run all Mojo-V tests ``` ```bash cd ../mojov-test make TARGET=mojov clean build test ``` -------------------------------- ### Build, Test, and Clean Bubble Sort Benchmark (Host Target) Source: https://github.com/toddmaustin/mojo-v/blob/main/bringup-bench/README.md This sequence of commands demonstrates how to build, test, and then clean the Bubble Sort benchmark specifically for the 'host' target. Each command performs a distinct operation in the benchmark lifecycle. ```makefile make TARGET=host build make TARGET=host test make TARGET=host clean ``` -------------------------------- ### Build, Test, and Clean a Benchmark Source: https://github.com/toddmaustin/mojo-v/blob/main/bringup-bench/README.md This command cleans the benchmark directory, builds the application for a specified target, and then tests its functionality. The '' parameter defines the environment for the build and test process. ```makefile make TARGET= clean build test ``` -------------------------------- ### Minimal System Dependencies for Bringup-Bench Source: https://github.com/toddmaustin/mojo-v/blob/main/bringup-bench/README.md Defines the four essential system call interfaces required for the Bringup-Bench to function: success, failure reporting, character output, and memory allocation. Optionally, performance monitoring hooks can be implemented. ```c /* benchmark completed successfully */ void libtarg_success(void); /* benchmark completed with error CODE */ void libtarg_fail(int code); /* output a single character, to wherever the target wants to send it... */ void libtarg_putc(char c); /* get some memory */ void *libtarg_sbrk(size_t inc); ``` ```c /* start perf-monitoring */ void libtarg_start_perf(); /* stop perf-monitoring */ void libtarg_stop_perf(); ``` -------------------------------- ### Hash-Alone Execution for Bare-Metal Benchmarks Source: https://github.com/toddmaustin/mojo-v/blob/main/bringup-bench/README.md Explains the concept of hash-alone execution, where benchmarks run in a bare-metal environment without I/O devices. Results are verified via a hash signature stored in '__hashval'. ```c /* When the libmin_success() interface is called, simply spin to terminate the program. */ /* At completion, the memory variable "__hashval" contains a hash signature of the output of the program as it run... */ ``` -------------------------------- ### Load Encrypted (LDE) Instruction for Secret Registers (RISC-V Assembly) Source: https://context7.com/toddmaustin/mojo-v/llms.txt This RISC-V assembly snippet demonstrates the usage of the LDE (Load Encrypted) instruction, which loads a 128-bit ciphertext from memory, decrypts it, and stores the 64-bit plaintext into a secret integer register. The example shows loading encrypted values, performing a secret comparison, and using conditional selection for oblivious operations. ```riscv-assembly // LDE instruction macro using .insn directive // Format: LDE(rd, base, offset) - Load encrypted into secret register rd from memory at base+offset #define LDE(rd, base, ofs) ".insn i 0xb, 0x0, " #rd ", " #base ", " #ofs "\n\t" // Example: Load encrypted values and perform secret comparison uint128_t encrypted_x, encrypted_max; __asm__ volatile ( // Load public values into non-secret registers, then store encrypted "ld t3, (%0)\n\t" // Load public x value SDE(t3, %2, 0) // Encrypt and store to encrypted_x "ld t3, (%1)\n\t" // Load public max value SDE(t3, %3, 0) // Encrypt and store to encrypted_max // Load encrypted values into secret registers LDE(x24, %2, 0) // x24 = decrypt(encrypted_x) - now x24 is SECRET LDE(x25, %3, 0) // x25 = decrypt(encrypted_max) - now x25 is SECRET // Perform secret comparison: is max < x? "slt x26, x25, x24\n\t" // x26 = (max < x) ? 1 : 0 - result is also SECRET // Data-oblivious conditional selection using Zicond "czero.eqz x24, x24, x26\n\t" // if x26==0 => x24=0, else x24=x "czero.nez x25, x25, x26\n\t" // if x26!=0 => x25=0, else x25=max "or x27, x24, x25\n\t" // x27 = (x if x>max else max) // Store result back as encrypted SDE(x27, %3, 0) : : "r"(&x), "r"(&max), "r"(&encrypted_x), "r"(&encrypted_max) : "t3", "x24", "x25", "x26", "x27" ); ``` -------------------------------- ### Define and Access In-Memory Read-Only Files (C) Source: https://github.com/toddmaustin/mojo-v/blob/main/bringup-bench/README.md Demonstrates how to define and access a read-only file embedded within benchmark code using the MFILE structure and associated library functions. ```c MFILE __mwords = { "words", __words_sz, __words, 0 }; MFILE *mwords = &__mwords; ``` ```c /* open an in-memory file */ void libmin_mopen(MFILE *mfile, const char *mode); /* return in-memory file size */ size_t libmin_msize(MFILE *mfile); /* at end of file */ int libmin_meof(MFILE *mfile); /* close the in-memory file */ void libmin_mclose(MFILE *mfile); /* read a buffer from the in-memory file */ size_t libmin_mread(void *ptr, size_t size, MFILE *mfile); /* get a string from the in-memory file */ char *libmin_mgets(char *s, size_t size, MFILE *mfile); /* read a character from the in-memory file */ int libmin_mgetc(MFILE *mfile); ``` -------------------------------- ### Compiling C Program for RISC-V Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md Commands to compile a C program and link it for the RISC-V architecture using GCC. It uses specific flags for debugging (-g, -Og) and a custom linker script. ```bash riscv64-unknown-elf-gcc -g -Og -o rot13-64.o -c rot13.c riscv64-unknown-elf-gcc -g -Og -T spike.lds -nostartfiles -o rot13-64 rot13-64.o ``` -------------------------------- ### Execute RISC-V Architectural Tests with Spike Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/arch_test_target/spike/README.md This command executes the RISC-V architectural tests using the configured Spike simulator. It assumes the test environment and Spike target have been properly set up. The sequence 'compile simulate verify' covers the entire testing pipeline. ```shell make compile simulate verify ``` -------------------------------- ### Running Spike for GDB Debugging Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md Command to launch the Spike simulator, enabling remote bitbang port for GDB connection. It specifies the memory size and base address for the program. ```bash spike --rbb-port=9824 -m0x10100000:0x20000 rot13-64 ``` -------------------------------- ### Run All Benchmarks for a Specific Target Source: https://github.com/toddmaustin/mojo-v/blob/main/bringup-bench/README.md This Makefile target automates the process of cleaning, building, and testing all benchmarks for a given target mode. It simplifies running comprehensive tests across different environments. ```makefile make TARGET= run-tests ``` -------------------------------- ### OpenOCD Configuration for Spike Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md Configuration file for OpenOCD to connect to Spike via remote bitbang. It sets up the JTAG tap and target for RISC-V debugging. ```tcl adapter driver remote_bitbang remote_bitbang host localhost remote_bitbang port 9824 set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0xdeadbeef set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME gdb_report_data_abort enable init halt ``` -------------------------------- ### Clone and Configure Spike for RISC-V Architectural Tests Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/arch_test_target/spike/README.md This snippet shows how to clone the RISC-V architectural test repository and copy the Spike target configuration file. It assumes Spike has already been built and its configuration path is known. The primary goal is to integrate Spike as a test target. ```shell $ git clone https://github.com/riscv/riscv-arch-test.git $ cd riscv-arch-test $ cp /riscv-isa-sim/arch_test_target/spike/Makefile.include . ``` -------------------------------- ### Define System Call Interfaces for Bringup-Bench (C) Source: https://github.com/toddmaustin/mojo-v/blob/main/bringup-bench/README.md Defines the four essential system call interfaces required for porting the Bringup-Bench. These functions handle benchmark status reporting (success/failure), character output, and memory allocation. They are crucial for the benchmark to interact with the target environment. ```c /* benchmark completed successfully */ void libtarg_success(void); /* benchmark completed with error CODE */ void libtarg_fail(int code); /* output a single character, to wherever the target wants to send it... */ void libtarg_putc(char c); /* get some memory */ void *libtarg_sbrk(size_t inc); ``` -------------------------------- ### RISC-V Linker Script (spike.lds) Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md A linker script for RISC-V that defines the memory layout for the program. It sets the program's entry point to 0x10110000 and defines the .text and .data sections. ```linker-script OUTPUT_ARCH( "riscv" ) SECTIONS { . = 0x10110000; .text : { *(.text) } .data : { *(.data) } } ``` -------------------------------- ### Convert File to Read-Only Code-Based File System (Python) Source: https://github.com/toddmaustin/mojo-v/blob/main/bringup-bench/README.md Converts an input file into a read-only code-based file format using a Python script. The output is a header file containing the data and its size, suitable for inclusion in benchmarks. ```python python3 scriptsr/file2hex.py words words.h __words ``` -------------------------------- ### Spike Interactive Debug Mode Commands Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md Commands to interact with the Spike simulator in debug mode. These commands allow inspection of registers, memory, and control of program execution flow. No external dependencies are required beyond launching Spike with the -d flag. ```spike-debug : reg 0 a0 : fregs 0 ft0 : fregd 0 ft0 : mem 2020 : mem 0 2020 : until pc 0 2020 : until reg 0 mie a : until mem 2020 50a9907311096993 : while mem 2020 50a9907311096993 : r : q ``` -------------------------------- ### C Program for GDB Debugging (rot13.c) Source: https://github.com/toddmaustin/mojo-v/blob/main/riscv-isa-sim/README.md A simple C program that performs a ROT13 cipher on a string. It's designed for debugging with GDB and Spike, intentionally avoiding stack usage and including a 'wait' variable for controlling execution. ```c char text[] = "Vafgehpgvba frgf jnag gb or serr!"; // Don't use the stack, because sp isn't set up. volatile int wait = 1; int main() { while (wait) ; // Doesn't actually go on the stack, because there are lots of GPRs. int i = 0; while (text[i]) { char lower = text[i] | 32; if (lower >= 'a' && lower <= 'm') text[i] += 13; else if (lower > 'm' && lower <= 'z') text[i] -= 13; i++; } done: while (!wait) ; } ``` -------------------------------- ### Clean All Benchmark Directories Source: https://github.com/toddmaustin/mojo-v/blob/main/bringup-bench/README.md This top-level Makefile target removes all generated files from benchmark directories across all supported targets. It's useful for ensuring a completely clean state before new builds. ```makefile make all-clean ``` -------------------------------- ### Data-Oblivious Bubble Sort with Mojo-V Assembly Source: https://context7.com/toddmaustin/mojo-v/llms.txt Implements a data-oblivious bubble sort algorithm using Mojo-V's secret computation capabilities. It leverages custom assembly instructions for encrypted operations, ensuring that the sorting process does not reveal information about the data's values. Dependencies include 'libmin.h' and 'simon.h' for cryptographic primitives and utility functions. ```c #include "libmin.h" #include "simon.h" typedef unsigned __int128 uint128_t; // Mojo-V instruction macros #define LDE(rd,base,ofs) ".insn i 0xb, 0x0, " #rd ", " #base ", " #ofs "\n\t" #define SDE(src,base,ofs) ".insn s 0xb, 0x1, " #src ", " #ofs "(" #base ")\n\t" #define CSR_MPRIVREGCFG 0x0a0 static inline void write_mprivregcfg(uint64_t value) { __asm__ volatile ("csrw %0, %1" :: "i"(CSR_MPRIVREGCFG), "rK"(value)); } #define DATASET_SIZE 256 uint64_t raw_data[DATASET_SIZE]; uint128_t secret_data[DATASET_SIZE]; uint128_t swaps; // Data-oblivious bubble sort - fixed access pattern regardless of data values void bubblesort(uint128_t *data, unsigned size) { for (unsigned i = 0; i < size - 1; i++) { for (unsigned j = 0; j < size - 1; j++) { __asm__ volatile ( // Load encrypted values into secret registers LDE(t3, %0, 0) // t3 = data[j] (SECRET) LDE(t4, %1, 0) // t4 = data[j+1] (SECRET) // Compare: swap = (data[j] > data[j+1]) "slt t5, t4, t3\n\t" // t5 = (t4 < t3) ? 1 : 0 (SECRET) // Conditional swap using Zicond (data-oblivious) "czero.eqz t6, t4, t5\n\t" // t6 = (t5==0) ? 0 : t4 "czero.nez t5, t3, t5\n\t" // t5 = (t5!=0) ? 0 : t3 "or t6, t5, t6\n\t" // t6 = new data[j] SDE(t6, %0, 0) // Store encrypted result // Compute new data[j+1] "slt t5, t4, t3\n\t" // Recompute predicate "czero.eqz t6, t3, t5\n\t" "czero.nez t3, t4, t5\n\t" "or t6, t3, t6\n\t" SDE(t6, %1, 0) // Store encrypted result // Update swap counter LDE(t3, %2, 0) // Load encrypted swap count "add t4, t3, t5\n\t" // Increment by swap flag SDE(t4, %2, 0) // Store updated count : : "r"(&data[j]), "r"(&data[j+1]), "r"(&swaps) : "t3", "t4", "t5", "t6" ); } } } int main(void) { // Initialize cipher for verification uint128_t key = GEN128(0x0f0e0d0c0b0a0908ULL, 0x0706050403020100ULL); simon_state_t state; simon_128_128_keyexpand(&state, key, 68); // Enable Mojo-V secret computation mode write_mprivregcfg(1); // Initialize encrypted array libmin_srand(42); for (unsigned i = 0; i < DATASET_SIZE; i++) { raw_data[i] = libmin_rand(); __asm__ volatile ( "ld t3, (%0)\n\t" SDE(t3, %1, 0) : : "r"(&raw_data[i]), "r"(&secret_data[i]) : "t3" ); } // Sort with constant-time, data-oblivious access pattern bubblesort(secret_data, DATASET_SIZE); // Disable Mojo-V (clears secret registers) write_mprivregcfg(0); // Verify results by decrypting for (unsigned i = 0; i < DATASET_SIZE; i++) { union { uint128_t ct; struct { uint64_t val; uint32_t salt; uint32_t sig; } pt; } m; simon_128_128_decrypt(&state, secret_data[i], &m.ct); raw_data[i] = m.pt.val; } // Check sorted for (unsigned i = 0; i < DATASET_SIZE - 1; i++) { if (raw_data[i] > raw_data[i + 1]) { libmin_printf("ERROR: Array not sorted\n"); return -1; } } libmin_printf("SUCCESS: Array sorted correctly\n"); return 0; } ``` -------------------------------- ### Simon-128 Cipher API Implementation in C Source: https://context7.com/toddmaustin/mojo-v/llms.txt Implements the Simon-128/128 cipher for Mojo-V's memory encryption. It includes functions for key expansion, encryption, and decryption of 128-bit blocks. This code requires the 'simon.h' header and defines the Mojo-V memory packet format. ```c #include "simon.h" // Simon state structure simon_state_t simon_state; // 128-bit key (split into high/low 64-bit halves) uint128_t simon_key = GEN128(0x0f0e0d0c0b0a0908ULL, 0x0706050403020100ULL); // Initialize the cipher with 68 rounds (full strength for 128/128) simon_128_128_keyexpand(&simon_state, simon_key, 68); // Mojo-V memory packet format union mojov_memfmt_t { uint128_t ct; // 128-bit ciphertext struct { uint64_t val; // 64-bit plaintext value (or double for FP) uint32_t salt; // Random salt for semantic security uint32_t sig; // Fixed signature (0xdeadbeef) for integrity } pt; }; // Decrypt a secret value for verification uint64_t secret_decrypt(uint128_t ct) { union mojov_memfmt_t mempkt; simon_128_128_decrypt(&simon_state, ct, &mempkt.ct); // Verify signature before trusting value if (mempkt.pt.sig != 0xdeadbeef) { // Invalid ciphertext - integrity check failed return 0; } return mempkt.pt.val; } // Encrypt a value for storage (for testing/verification only) uint128_t secret_encrypt(uint64_t val, uint32_t salt) { union mojov_memfmt_t mempkt = { .pt = { .val = val, .salt = salt, .sig = 0xdeadbeef } }; uint128_t ct; simon_128_128_encrypt(&simon_state, mempkt.ct, &ct); return ct; } ``` -------------------------------- ### Store Encrypted Integer (SDE) using C Source: https://context7.com/toddmaustin/mojo-v/llms.txt The SDE instruction encrypts an integer from a register and stores it to memory. It supports both secret and non-secret source registers. Non-secret registers produce fresh ciphertexts upon each encryption. ```c #define SDE(src, base, ofs) ".insn s 0xb, 0x1, " #src ", " #ofs "(" #base ")\n\t" // Example: Encrypt public data for third-party storage uint64_t public_data = 42; uint128_t encrypted_storage; __asm__ volatile ( // Load public value and encrypt it for storage "ld t3, (%0)\n\t" // Load public value SDE(t3, %1, 0) // Encrypt and store (t3 is non-secret, so creates fresh ciphertext) : : "r"(&public_data), "r"(&encrypted_storage) : "t3" ); // Later: Load encrypted value into secret register for computation __asm__ volatile ( LDE(x28, %0, 0) // Decrypt into secret register x28 "addi x28, x28, 10\n\t" // Secret computation: add 10 SDE(x28, %1, 0) // Re-encrypt and store result : : "r"(&encrypted_storage), "r"(&encrypted_result) : "x28" ); ```