diff --git a/templates/gapuino/.gitignore b/templates/gapuino/.gitignore new file mode 100644 index 0000000..03f4a3c --- /dev/null +++ b/templates/gapuino/.gitignore @@ -0,0 +1 @@ +.pio diff --git a/templates/gapuino/.travis.yml b/templates/gapuino/.travis.yml new file mode 100644 index 0000000..7c486f1 --- /dev/null +++ b/templates/gapuino/.travis.yml @@ -0,0 +1,67 @@ +# Continuous Integration (CI) is the practice, in software +# engineering, of merging all developer working copies with a shared mainline +# several times a day < https://docs.platformio.org/page/ci/index.html > +# +# Documentation: +# +# * Travis CI Embedded Builds with PlatformIO +# < https://docs.travis-ci.com/user/integration/platformio/ > +# +# * PlatformIO integration with Travis CI +# < https://docs.platformio.org/page/ci/travis.html > +# +# * User Guide for `platformio ci` command +# < https://docs.platformio.org/page/userguide/cmd_ci.html > +# +# +# Please choose one of the following templates (proposed below) and uncomment +# it (remove "# " before each line) or use own configuration according to the +# Travis CI documentation (see above). +# + + +# +# Template #1: General project. Test it using existing `platformio.ini`. +# + +# language: python +# python: +# - "2.7" +# +# sudo: false +# cache: +# directories: +# - "~/.platformio" +# +# install: +# - pip install -U platformio +# - platformio update +# +# script: +# - platformio run + + +# +# Template #2: The project is intended to be used as a library with examples. +# + +# language: python +# python: +# - "2.7" +# +# sudo: false +# cache: +# directories: +# - "~/.platformio" +# +# env: +# - PLATFORMIO_CI_SRC=path/to/test/file.c +# - PLATFORMIO_CI_SRC=examples/file.ino +# - PLATFORMIO_CI_SRC=path/to/test/directory +# +# install: +# - pip install -U platformio +# - platformio update +# +# script: +# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N diff --git a/templates/gapuino/Makefile b/templates/gapuino/Makefile new file mode 100644 index 0000000..46a895e --- /dev/null +++ b/templates/gapuino/Makefile @@ -0,0 +1,13 @@ +LFLAGS=-lm +all: gapuino + +gapuino: .pioenvs/gapuino/firmware.bin + +.pioenvs/gapuino/firmware.bin: FORCE + platformio run -e gapuino + +FORCE: ; +.PHONY: clean + +clean: + -rm .pioenvs/gapuino/firmware.bin diff --git a/templates/gapuino/configure b/templates/gapuino/configure new file mode 100755 index 0000000..d3c9b5f --- /dev/null +++ b/templates/gapuino/configure @@ -0,0 +1,5 @@ +#!/bin/bash +mv -n *.c *.s *.S src/ +mv -n *.dat *.inc *.h include/ +sed -i src/encrypt.c -e "s/\(\s\)init(/\1_init(/g" +exit 0 diff --git a/templates/gapuino/include/crypto_aead.h b/templates/gapuino/include/crypto_aead.h new file mode 100644 index 0000000..651490c --- /dev/null +++ b/templates/gapuino/include/crypto_aead.h @@ -0,0 +1,26 @@ +#ifdef __cplusplus +extern "C" { +#endif + +int crypto_aead_encrypt( + unsigned char *c,unsigned long long *clen, + const unsigned char *m,unsigned long long mlen, + const unsigned char *ad,unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k + ); + + +int crypto_aead_decrypt( + unsigned char *m,unsigned long long *outputmlen, + unsigned char *nsec, + const unsigned char *c,unsigned long long clen, + const unsigned char *ad,unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k + ); + +#ifdef __cplusplus +} +#endif diff --git a/templates/gapuino/include/uartp.h b/templates/gapuino/include/uartp.h new file mode 100644 index 0000000..3a80a60 --- /dev/null +++ b/templates/gapuino/include/uartp.h @@ -0,0 +1,11 @@ +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +void uartp_send(const void *src, uint16_t len); +uint16_t uartp_recv(void *dst, uint16_t buf_len); + +#ifdef __cplusplus +} +#endif diff --git a/templates/gapuino/platformio.ini b/templates/gapuino/platformio.ini new file mode 100644 index 0000000..54a9abc --- /dev/null +++ b/templates/gapuino/platformio.ini @@ -0,0 +1,15 @@ +;PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:gapuino] +platform = riscv_gap +board = gapuino +framework = mbed + diff --git a/templates/gapuino/src/main.ino b/templates/gapuino/src/main.ino new file mode 100644 index 0000000..c420b11 --- /dev/null +++ b/templates/gapuino/src/main.ino @@ -0,0 +1,117 @@ +#include "crypto_aead.h" +#include "api.h" +#include "uartp.h" +#include "mbed.h" + +#define MAX_BYTES 100 +#define CMDBUF_LEN 72 +static uint8_t cmdbuf[CMDBUF_LEN]; + +#define CRYPTO_BUSY GPIO_A23 + +Serial device(USBTX, USBRX); + +uint8_t npub[CRYPTO_NPUBBYTES]; +uint8_t nsec[CRYPTO_NSECBYTES]; +uint8_t k[CRYPTO_KEYBYTES]; +uint8_t ad[MAX_BYTES]; +uint8_t m[MAX_BYTES]; +uint8_t c[MAX_BYTES]; +unsigned long long int adlen = 0; +unsigned long long int mlen = 0; +unsigned long long int clen = 0; +int res = 0; + +void setup(); +void loop(); + +#ifdef __cplusplus +extern "C" { +#endif + +void uart_wbyte(uint8_t x) { + device.putc((uint8_t) (x)); +} + +uint8_t uart_rbyte() { + int r; + do { + r = device.getc(); + } while (r == -1); + return (uint8_t) (0xff & r); +} + +#ifdef __cplusplus +} +#endif + +void my_assert(bool b) { + if (b) + return; + for(;;) + yield(); +} + +void setup() { + device.baud(115200); + DigitalOut crypto_pin(CRYPTO_BUSY); + crypto_pin = 1; + wait(100); + memset(npub, 0, CRYPTO_NPUBBYTES); + memset(nsec, 0, CRYPTO_NSECBYTES); + memset(k, 0, CRYPTO_KEYBYTES); + memset(ad, 0, MAX_BYTES); + memset(m, 0, MAX_BYTES); + memset(c, 0, MAX_BYTES); + device.printf("Hello, World!"); +} + +void loop() { + int res; + uint16_t len = uartp_recv(cmdbuf, CMDBUF_LEN - 1); + uint8_t action = cmdbuf[0]; + if (len == 0 || len > CMDBUF_LEN - 1) + return; + + uint16_t l = len - 1; + uint16_t rl = 0; + uint8_t *var = cmdbuf+1; + switch (action) { + case 'm': my_assert(l <= MAX_BYTES); memcpy(m, var, l); mlen = l; break; + case 'c': my_assert(l <= MAX_BYTES); memcpy(c, var, l); clen = l; break; + case 'a': my_assert(l <= MAX_BYTES); memcpy(ad, var, l); adlen = l; break; + case 'k': my_assert(l == CRYPTO_KEYBYTES); memcpy(k, var, l); break; + case 'p': my_assert(l == CRYPTO_NPUBBYTES); memcpy(npub, var, l); break; + case 's': my_assert(l == CRYPTO_NSECBYTES); memcpy(nsec, var, l); break; + case 'e': + __disable_irq(); + __NOP(); + crypto_pin = 0; + res = crypto_aead_encrypt(c, &clen, m, mlen, ad, adlen, nsec, npub, k); + crypto_pin = 1; + __NOP(); + __enable_irq(); + break; + case 'd': + __disable_irq(); + __NOP(); + crypto_pin = 0; + res = crypto_aead_decrypt(m, &mlen, nsec, c, clen, ad, adlen, npub, k); + crypto_pin = 1; + __NOP(); + __enable_irq(); + break; + case'M': var = m; rl = mlen; break; + case'C': var = c; rl = clen; break; + case'A': var = ad; rl = adlen; break; + case'K': var = k; rl = CRYPTO_KEYBYTES; break; + case'P': var = npub; rl = CRYPTO_NPUBBYTES; break; + case'S': var = nsec; rl = CRYPTO_NSECBYTES; break; + case'R': var = (uint8_t *) &res; rl = sizeof(res); break; + default: + my_assert(false); + } + cmdbuf[0] = action; + memcpy(cmdbuf+1, var, rl); + uartp_send(cmdbuf, rl+1); +} diff --git a/templates/gapuino/src/uartp.c b/templates/gapuino/src/uartp.c new file mode 100644 index 0000000..e520cfc --- /dev/null +++ b/templates/gapuino/src/uartp.c @@ -0,0 +1,75 @@ +#include +#include "uartp.h" + +extern void uart_wbyte(uint8_t x); +extern uint8_t uart_rbyte(); + +// Simple serial protocol with packets and checksum +const uint8_t AMUX_TAG = 0xf9; +const uint8_t AMUX_END = 0xf3; +const uint8_t AMUX_EXT = 0x80; + +void uartp_send(const void *src, uint16_t len) { + uint8_t len_ind_0, len_ind_1, fcs, info; + const uint8_t *buf = (const uint8_t *) src; + + uart_wbyte(AMUX_TAG); + len_ind_0 = (uint8_t) (0xff & len); + len_ind_1 = (uint8_t) (0xff & (len >> 7)); + if (len < 128) { + uart_wbyte(len_ind_0); + } else { + uart_wbyte(len_ind_0 | AMUX_EXT); + uart_wbyte(len_ind_1); + } + fcs = 0; + for (uint16_t i = 0; i < len; i++) { + info = buf[i]; + fcs += info; + uart_wbyte(buf[i]); + } + fcs = 255 - fcs; + uart_wbyte(fcs); + uart_wbyte(AMUX_END); +} + + +uint16_t uartp_recv(void *dst, uint16_t buf_len) { + uint8_t *buf = (uint8_t *) dst; + uint8_t tag, info, cs; + uint16_t len; + + tag = AMUX_END; + while (1) { + + do { + tag = uart_rbyte(); + } while(tag != AMUX_TAG); + + len = (uint16_t) uart_rbyte(); + if (len & AMUX_EXT) { + len &= (~AMUX_EXT); + len |= (uint16_t) (uart_rbyte() << 7); + } + if (len > buf_len) { + return len; + } + + uint16_t i = 0; + cs = 0; + for (i = 0; i < len; i++) { + info = uart_rbyte(); + buf[i] = info; + cs += info; + } + cs += uart_rbyte(); + tag = uart_rbyte(); + if (0xff == cs) { + if (AMUX_END == tag) { + return len; + } + } + + } +} + diff --git a/templates/gapuino/test b/templates/gapuino/test new file mode 100755 index 0000000..35a54c3 --- /dev/null +++ b/templates/gapuino/test @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 + +import os +import sys +import time +import struct +import serial +import subprocess + + + +def eprint(*args, **kargs): + print(*args, file=sys.stderr, **kargs) + + +def flash(tty=None): + pipe = subprocess.PIPE + cmd = ['platformio', 'run', '--target', 'upload'] + if tty is not None: + cmd.extend(['--upload-port', tty]) + p = subprocess.Popen(cmd, + stdout=sys.stderr, stdin=pipe) + stdout, stderr = p.communicate("") + +def get_serial(): + import serial.tools.list_ports + ports = serial.tools.list_ports.comports() + devices = [ p.device for p in ports ] + devices.sort() + # Might also be 0, one is JTAG, one UART + return devices[-1] + + +class UARTP: + def __init__(self, ser): + UARTP.SYN = 0xf9 + UARTP.FIN = 0xf3 + self.ser = ser + + def uart_read(self): + r = self.ser.read(1) + if len(r) != 1: + raise Exception("Serial read error") + return r[0] + + def uart_write(self, c): + b = struct.pack("B", c) + r = self.ser.write(b) + if r != len(b): + raise Exception("Serial write error") + return r + + def send(self, buf): + self.uart_write(UARTP.SYN) + len_ind_0 = 0xff & len(buf) + len_ind_1 = 0xff & (len(buf) >> 7) + if len(buf) < 128: + self.uart_write(len_ind_0) + else: + self.uart_write(len_ind_0 | 0x80) + self.uart_write(len_ind_1) + fcs = 0 + for i in range(len(buf)): + info = buf[i] + fcs = (fcs + info) & 0xff + self.uart_write(buf[i]) + fcs = (0xff - fcs) & 0xff + self.uart_write(fcs) + self.uart_write(UARTP.FIN) + eprint("sent frame '%s'" % buf.hex()) + + def recv(self): + tag_old = UARTP.FIN + while 1: + tag = tag_old + while 1: + if tag_old == UARTP.FIN: + if tag == UARTP.SYN: + break + tag_old = tag + tag = self.uart_read() + tag_old = tag + + l = self.uart_read() + if l & 0x80: + l &= 0x7f + l |= self.uart_read() << 7 + + fcs = 0 + buf = [] + for i in range(l): + info = self.uart_read() + buf.append(info) + fcs = (fcs + info) & 0xff + fcs = (fcs + self.uart_read()) & 0xff + + tag = self.uart_read() + if fcs == 0xff: + if tag == UARTP.FIN: + buf = bytes(buf) + eprint("rcvd frame '%s'" % buf.hex()) + if len(buf) >= 1 and buf[0] == 0xde: + sys.stderr.buffer.write(buf[1:]) + sys.stderr.flush() + else: + return buf + + +def stdin_read(n): + b = sys.stdin.buffer.read(n) + if len(b) != n: + sys.exit(1) + return b + + +def stdin_readvar(): + l = stdin_read(4) + (l, ) = struct.unpack(" 0: + os.chdir(script_dir) + + + dev = get_serial() + flash(dev) + eprint("Flashed") + time.sleep(0.1) + ser = serial.Serial(dev, baudrate=1500000, timeout=5) + uartp = UARTP(ser) + + ser.setRTS(True) + time.sleep(0.1) + ser.setRTS(False) + time.sleep(0.1) + ser.setRTS(True) + time.sleep(1) + + exp_hello = b"Hello, World!" + hello = ser.read(len(exp_hello)) + if hello != exp_hello: + eprint("Improper board initialization message: ") + return 1 + eprint("Board initialized properly") + sys.stdout.write("Hello, World!\n") + sys.stdout.flush() + + while 1: + action = stdin_read(1)[0] + eprint("Command %c from stdin" % action) + + if action in b"ackmps": + v = stdin_readvar() + uartp.send(struct.pack("B", action) + v) + ack = uartp.recv() + if len(ack) != 1 or ack[0] != action: + raise Exception("Unacknowledged variable transfer") + eprint("Var %c successfully sent to board" % action) + + elif action in b"ACKMPS": + c = struct.pack("B", action) + uartp.send(c) + v = uartp.recv() + if len(v) < 1 or v[0] != action: + raise Exception("Could not obtain variable from board") + v = v[1:] + eprint("Var %c received from board: %s" % (action, v.hex())) + l = struct.pack("