diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 0ab90f3114..fea2bd8ff5 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -57,3 +57,24 @@ jobs: override: true - name: Create Doc run: cargo doc + Embedded: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up QEMU + run: sudo apt update && sudo apt install qemu-system-arm gcc-arm-none-eabi + - name: Checkout Toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + components: rust-src + target: thumbv7m-none-eabi + - name: Run + env: + RUSTFLAGS: "-C link-arg=-Tlink.x" + CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER: "qemu-system-arm -cpu cortex-m3 -machine mps2-an385 -m 1G -nographic -semihosting-config enable=on,target=native -kernel" + run: cd embedded && cargo run --target thumbv7m-none-eabi + diff --git a/embedded/Cargo.toml b/embedded/Cargo.toml new file mode 100644 index 0000000000..f8c870b367 --- /dev/null +++ b/embedded/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["Riccardo Casatta ", "Dev Random "] +edition = "2018" +readme = "README.md" +name = "embedded" +version = "0.1.0" + +[dependencies] +cortex-m = "0.6.0" +cortex-m-rt = "0.6.10" +cortex-m-semihosting = "0.3.3" +panic-halt = "0.2.0" +alloc-cortex-m = "0.4.1" +bitcoin = { path="../", default-features = false, features = ["no-std", "secp-lowmemory"] } + +[[bin]] +name = "embedded" +test = false +bench = false + +[profile.release] +codegen-units = 1 # better optimizations +debug = true # symbols are nice and they don't increase the size on Flash +lto = true # better optimizations diff --git a/embedded/README.md b/embedded/README.md new file mode 100644 index 0000000000..bfc433fe71 --- /dev/null +++ b/embedded/README.md @@ -0,0 +1,25 @@ +# Running + +To run the embedded test, first prepare your environment: + +```shell +sudo ./scripts/install-deps +rustup target add thumbv7m-none-eabi +``` + +Then: + +```shell +source ./scripts/env.sh && cargo run --target thumbv7m-none-eabi +``` + +Output should be something like: + +```text +heap size 524288 +secp buf size 66240 +Seed WIF: L1HKVVLHXiUhecWnwFYF6L3shkf1E12HUmuZTESvBXUdx3yqVP1D +Address: bc1qpx9t9pzzl4qsydmhyt6ctrxxjd4ep549np9993 +``` + +Note that this heap size is required because of the amount of stack used by libsecp256k1 when initializing a context. diff --git a/embedded/memory.x b/embedded/memory.x new file mode 100644 index 0000000000..a07f29cff7 --- /dev/null +++ b/embedded/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 512K + RAM : ORIGIN = 0x20000000, LENGTH = 512K +} diff --git a/embedded/scripts/env.sh b/embedded/scripts/env.sh new file mode 100644 index 0000000000..d72a093292 --- /dev/null +++ b/embedded/scripts/env.sh @@ -0,0 +1,2 @@ +export RUSTFLAGS="-C link-arg=-Tlink.x" +export CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER="qemu-system-arm -cpu cortex-m3 -machine mps2-an385 -m 1G -nographic -semihosting-config enable=on,target=native -kernel" diff --git a/embedded/scripts/install-deps b/embedded/scripts/install-deps new file mode 100755 index 0000000000..d22806ddb5 --- /dev/null +++ b/embedded/scripts/install-deps @@ -0,0 +1,3 @@ +#!/bin/sh + +apt install gcc-arm-none-eabi qemu-system-arm gdb-multiarch diff --git a/embedded/src/main.rs b/embedded/src/main.rs new file mode 100644 index 0000000000..c7cc5bdcf2 --- /dev/null +++ b/embedded/src/main.rs @@ -0,0 +1,76 @@ +#![feature(alloc_error_handler)] +#![feature(panic_info_message)] +#![no_std] +#![no_main] + +extern crate alloc; +extern crate bitcoin; + +use alloc::string::ToString; +use alloc::vec; +use core::alloc::Layout; +use core::panic::PanicInfo; + +use alloc_cortex_m::CortexMHeap; +// use panic_halt as _; +use bitcoin::{Address, Network, PrivateKey}; +use bitcoin::secp256k1::ffi::types::AlignedType; +use bitcoin::secp256k1::Secp256k1; + +use cortex_m::asm; +use cortex_m_rt::entry; +use cortex_m_semihosting::{debug, hprintln}; + +// this is the allocator the application will use +#[global_allocator] +static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); + +const HEAP_SIZE: usize = 1024 * 512; // 512 KB + +#[entry] +fn main() -> ! { + hprintln!("heap size {}", HEAP_SIZE).unwrap(); + + unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) } + + let size = Secp256k1::preallocate_size(); + hprintln!("secp buf size {}", size*16).unwrap(); + + // Load a private key + let raw = "L1HKVVLHXiUhecWnwFYF6L3shkf1E12HUmuZTESvBXUdx3yqVP1D"; + let pk = PrivateKey::from_wif(raw).unwrap(); + hprintln!("Seed WIF: {}", pk).unwrap(); + + let mut buf_ful = vec![AlignedType::zeroed(); size]; + let secp = Secp256k1::preallocated_new(&mut buf_ful).unwrap(); + + // Derive address + let pubkey = pk.public_key(&secp); + let address = Address::p2wpkh(&pubkey, Network::Bitcoin).unwrap(); + hprintln!("Address: {}", address).unwrap(); + + assert_eq!(address.to_string(), "bc1qpx9t9pzzl4qsydmhyt6ctrxxjd4ep549np9993".to_string()); + // exit QEMU + // NOTE do not run this on hardware; it can corrupt OpenOCD state + debug::exit(debug::EXIT_SUCCESS); + + loop {} +} + +// define what happens in an Out Of Memory (OOM) condition +#[alloc_error_handler] +fn alloc_error(_layout: Layout) -> ! { + hprintln!("alloc error").unwrap(); + debug::exit(debug::EXIT_FAILURE); + asm::bkpt(); + + loop {} +} + +#[inline(never)] +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + hprintln!("panic {:?}", info.message()).unwrap(); + debug::exit(debug::EXIT_FAILURE); + loop {} +}