Merge branch 'main' of github.com:tillitis/tillitis-key1

This commit is contained in:
Joachim Strömbergson 2022-11-09 15:06:07 +01:00
commit 1a49304224
11 changed files with 72 additions and 24 deletions

2
.gitignore vendored
View File

@ -64,3 +64,5 @@ fp-info-cache
*.net *.net
*.dsn *.dsn
*.ses *.ses
__pycache__

View File

@ -18,8 +18,10 @@ user-provided seed, is used to derive key material unique to each
application. This allows users to build and load their own apps, while application. This allows users to build and load their own apps, while
ensuring that each app loaded will have its own cryptographic ensuring that each app loaded will have its own cryptographic
identity. The design is similar to TCG DICE. The Tillitis Key 1 identity. The design is similar to TCG DICE. The Tillitis Key 1
platform has 128 KB of RAM. The current firmware design allows for platform has 128 KB of RAM. The current firmware is designed to load
applications up to 64 KB with a 64 KB stack. an app that is up to 100 KB in size, and gives it a stack of 28 KB. A
smaller app may want to move itself in memory to get larger continuous
memory.
![Tillitis Key 1 PCB, first implementation](doc/images/mta1-usb-v1.jpg) ![Tillitis Key 1 PCB, first implementation](doc/images/mta1-usb-v1.jpg)
*Tillitis Key 1 PCB, first implementation* *Tillitis Key 1 PCB, first implementation*

View File

@ -35,7 +35,10 @@ the touch sensor is located (next to the LED). Note that connecting
the USB stick to the computer is not required for programming it. Note the USB stick to the computer is not required for programming it. Note
also that with this setup, to reset the USB stick back to firmware also that with this setup, to reset the USB stick back to firmware
mode after loading an app, you need to unplug both the USB cable to mode after loading an app, you need to unplug both the USB cable to
the stick and the one to the programmer. the stick and the one to the programmer. Alternatively, you can try
the script in `../hw/application_fpga/tools/reset-tk1` which pokes at
the TK1 that's sitting in the jig, leaving it in firmware mode so that
a new app can be loaded.
On Linux, `lsusb` should list the connected programmer as `cafe:4004 On Linux, `lsusb` should list the connected programmer as `cafe:4004
Blinkinlabs ICE40 programmer`. If the USB stick is also connected it Blinkinlabs ICE40 programmer`. If the USB stick is also connected it

View File

@ -63,7 +63,9 @@ between the host and the device.
## Firmware ## Firmware
The device has 128 KB RAM. The current firmware loads the app at the The device has 128 KB RAM. The current firmware loads the app at the
upper 64 KB. The lower 64 KB is currently set up as stack for the app. upper 100 KB. The lower 28 KB is set up as stack for the app. A
smaller app that wants continuous memory may want to relocate itself
when starting.
The firmware is part of FPGA bitstream (ROM), and is loaded at The firmware is part of FPGA bitstream (ROM), and is loaded at
`0x0000_0000`. `0x0000_0000`.
@ -73,7 +75,7 @@ The firmware is part of FPGA bitstream (ROM), and is loaded at
The PicoRV32 starts executing at `0x0000_0000`. Our firmware starts at The PicoRV32 starts executing at `0x0000_0000`. Our firmware starts at
`_start` from `start.S` which initializes the `.data`, and `.bss` at `_start` from `start.S` which initializes the `.data`, and `.bss` at
`0x4000_0000` and upwards. A stack is also initialized, starting at `0x4000_0000` and upwards. A stack is also initialized, starting at
0x4000_fff0 and downwards. When the initialization is finished, the 0x4000_6ff0 and downwards. When the initialization is finished, the
firmware waits for incoming commands from the host, by busy-polling firmware waits for incoming commands from the host, by busy-polling
the `UART_RX_{STATUS,DATA}` registers. When a complete command is the `UART_RX_{STATUS,DATA}` registers. When a complete command is
read, the firmware executes the command. read, the firmware executes the command.
@ -81,7 +83,7 @@ read, the firmware executes the command.
### Loading an application ### Loading an application
The purpose of the firmware is to bootstrap an application. The host The purpose of the firmware is to bootstrap an application. The host
will send a raw binary targeted to be loaded at `0x4001_0000` in the will send a raw binary targeted to be loaded at `0x4000_7000` in the
device. device.
1. The host sends the User Supplied Secret (USS) by using the 1. The host sends the User Supplied Secret (USS) by using the
@ -96,7 +98,7 @@ device.
multiple `FW_CMD_LOAD_APP_DATA` commands, together containing the multiple `FW_CMD_LOAD_APP_DATA` commands, together containing the
full application. full application.
5. For each received `FW_CMD_LOAD_APP_DATA` command the firmware 5. For each received `FW_CMD_LOAD_APP_DATA` command the firmware
places the data into `0x4001_0000` and upwards. The firmware places the data into `0x4000_7000` and upwards. The firmware
replies with a `FW_RSP_LOAD_APP_DATA` response to the host for replies with a `FW_RSP_LOAD_APP_DATA` response to the host for
each received block. each received block.
6. When the final block of the application image is received, we 6. When the final block of the application image is received, we
@ -105,7 +107,7 @@ device.
The Compound Device Identifier is computed by using the `UDS`, The Compound Device Identifier is computed by using the `UDS`,
the measurement of the application, and the `USS`, and placed in the measurement of the application, and the `USS`, and placed in
the `CDI` register. Then `0x4001_0000` is written to `APP_ADDR`. the `CDI` register. Then `0x4000_7000` is written to `APP_ADDR`.
The final `FW_RSP_LOAD_APP_DATA` response is sent to the host, The final `FW_RSP_LOAD_APP_DATA` response is sent to the host,
completing the loading. completing the loading.
@ -355,8 +357,8 @@ Assigned core prefixes:
| | | | | | | returns 0 if device is in firmware mode, 0xffffffff if in app mode. | | | | | | | | returns 0 if device is in firmware mode, 0xffffffff if in app mode. |
| `LED` | w | w | 1B | u8 | | | | `LED` | w | w | 1B | u8 | | |
| `GPIO` | | | | | | | | `GPIO` | | | | | | |
| `APP_ADDR` | r/w | r | 4B | u32 | | Application address (0x4000_0000) | | `APP_ADDR` | r/w | r | 4B | u32 | | Firmware stores app load address here, so app can read its own location|
| `APP_SIZE` | r/w | r | 4B | u32 | | Application size | | `APP_SIZE` | r/w | r | 4B | u32 | | Firmware stores app app size here, so app can read its own size |
| `CDI_FIRST` | r/w | r | 32B | u8[32] | | Compound Device Identifier (CDI). UDS+measurement... | | `CDI_FIRST` | r/w | r | 32B | u8[32] | | Compound Device Identifier (CDI). UDS+measurement... |
| `CDI_LAST` | | r | | | | Last word of CDI | | `CDI_LAST` | | r | | | | Last word of CDI |

View File

@ -9,10 +9,6 @@
#include "proto.h" #include "proto.h"
#include "types.h" #include "types.h"
// In RAM + above the stack (0x40010000)
#define APP_RAM_ADDR (TK1_RAM_BASE + 0x10000)
#define APP_MAX_SIZE 65536
// clang-format off // clang-format off
static volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST; static volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST;
static volatile uint32_t *switch_app = (volatile uint32_t *)TK1_MMIO_TK1_SWITCH_APP; static volatile uint32_t *switch_app = (volatile uint32_t *)TK1_MMIO_TK1_SWITCH_APP;
@ -95,7 +91,7 @@ int main()
struct frame_header hdr; // Used in both directions struct frame_header hdr; // Used in both directions
uint8_t cmd[CMDLEN_MAXBYTES]; uint8_t cmd[CMDLEN_MAXBYTES];
uint8_t rsp[CMDLEN_MAXBYTES]; uint8_t rsp[CMDLEN_MAXBYTES];
uint8_t *loadaddr = (uint8_t *)APP_RAM_ADDR; uint8_t *loadaddr = (uint8_t *)TK1_APP_ADDR;
int left = 0; // Bytes left to receive int left = 0; // Bytes left to receive
uint8_t uss[32] = {0}; uint8_t uss[32] = {0};
uint8_t digest[32] = {0}; uint8_t digest[32] = {0};
@ -177,7 +173,7 @@ int main()
putinthex(local_app_size); putinthex(local_app_size);
lf(); lf();
if (local_app_size > APP_MAX_SIZE) { if (local_app_size > TK1_APP_MAX_SIZE) {
rsp[0] = STATUS_BAD; rsp[0] = STATUS_BAD;
fwreply(hdr, FW_RSP_LOAD_APP_SIZE, rsp); fwreply(hdr, FW_RSP_LOAD_APP_SIZE, rsp);
break; break;
@ -190,7 +186,7 @@ int main()
memset(digest, 0, 32); memset(digest, 0, 32);
// Reset where to start loading the program // Reset where to start loading the program
loadaddr = (uint8_t *)APP_RAM_ADDR; loadaddr = (uint8_t *)TK1_APP_ADDR;
left = *app_size; left = *app_size;
rsp[0] = STATUS_OK; rsp[0] = STATUS_OK;
@ -224,7 +220,7 @@ int main()
putinthex(*app_size); putinthex(*app_size);
lf(); lf();
*app_addr = APP_RAM_ADDR; *app_addr = TK1_APP_ADDR;
// Get the Blake2S digest of the app - store it // Get the Blake2S digest of the app - store it
// for later queries // for later queries
blake2s_ctx ctx; blake2s_ctx ctx;
@ -266,8 +262,9 @@ int main()
lf(); lf();
// clang-format off // clang-format off
asm volatile( asm volatile(
// Clear the stack
"li a0, 0x40000000;" // TK1_RAM_BASE "li a0, 0x40000000;" // TK1_RAM_BASE
"li a1, 0x40010000;" "li a1, 0x40007000;" // APP_RAM_ADDR
"loop:;" "loop:;"
"sw zero, 0(a0);" "sw zero, 0(a0);"
"addi a0, a0, 4;" "addi a0, a0, 4;"

View File

@ -39,15 +39,15 @@ _start:
li x31,0 li x31,0
/* Clear all RAM */ /* Clear all RAM */
li a0, 0x40000000 // RAM base li a0, 0x40000000 // TK1_RAM_BASE
li a1, 0x40020000 // To end of SRAM li a1, 0x40020000 // TK1_RAM_BASE + TK1_RAM_SIZE
clear: clear:
sw zero, 0(a0) sw zero, 0(a0)
addi a0, a0, 4 addi a0, a0, 4
blt a0, a1, clear blt a0, a1, clear
/* init stack to right under where we load app at 0x40010000 */ /* init stack below 0x40007000 (TK1_APP_ADDR) where we load app */
li sp, 0x4000fff0 li sp, 0x40006ff0
/* copy data section */ /* copy data section */
la a0, _sidata la a0, _sidata

View File

@ -20,10 +20,14 @@
enum { enum {
TK1_ROM_BASE = 0x00000000, // 0b00000000... TK1_ROM_BASE = 0x00000000, // 0b00000000...
TK1_RAM_BASE = 0x40000000, // 0b01000000... TK1_RAM_BASE = 0x40000000, // 0b01000000...
TK1_RAM_SIZE = 0x20000, // 128 KB
TK1_RESERVED_BASE = 0x80000000, // 0b10000000... TK1_RESERVED_BASE = 0x80000000, // 0b10000000...
TK1_MMIO_BASE = 0xc0000000, // 0b11000000... TK1_MMIO_BASE = 0xc0000000, // 0b11000000...
TK1_MMIO_SIZE = 0xffffffff - TK1_MMIO_BASE, TK1_MMIO_SIZE = 0xffffffff - TK1_MMIO_BASE,
TK1_APP_ADDR = TK1_RAM_BASE + 0x7000, // 28 KB of stack
TK1_APP_MAX_SIZE = TK1_RAM_SIZE - (TK1_APP_ADDR - TK1_RAM_BASE),
TK1_MMIO_TRNG_BASE = TK1_MMIO_BASE | 0x00000000, TK1_MMIO_TRNG_BASE = TK1_MMIO_BASE | 0x00000000,
TK1_MMIO_TIMER_BASE = TK1_MMIO_BASE | 0x01000000, TK1_MMIO_TIMER_BASE = TK1_MMIO_BASE | 0x01000000,
TK1_MMIO_UDS_BASE = TK1_MMIO_BASE | 0x02000000, TK1_MMIO_UDS_BASE = TK1_MMIO_BASE | 0x02000000,
@ -81,7 +85,7 @@ enum {
TK1_MMIO_TK1_GPIO2_BIT = 1, TK1_MMIO_TK1_GPIO2_BIT = 1,
TK1_MMIO_TK1_GPIO3_BIT = 2, TK1_MMIO_TK1_GPIO3_BIT = 2,
TK1_MMIO_TK1_GPIO4_BIT = 3, TK1_MMIO_TK1_GPIO4_BIT = 3,
TK1_MMIO_TK1_APP_ADDR = TK1_MMIO_TK1_BASE | 0x30, // 0x4000_0000 TK1_MMIO_TK1_APP_ADDR = TK1_MMIO_TK1_BASE | 0x30,
TK1_MMIO_TK1_APP_SIZE = TK1_MMIO_TK1_BASE | 0x34, TK1_MMIO_TK1_APP_SIZE = TK1_MMIO_TK1_BASE | 0x34,
TK1_MMIO_TK1_CDI_FIRST = TK1_MMIO_TK1_BASE | 0x80, TK1_MMIO_TK1_CDI_FIRST = TK1_MMIO_TK1_BASE | 0x80,
TK1_MMIO_TK1_CDI_LAST = TK1_MMIO_TK1_BASE | 0x9c, // Address of last 32-bit word of CDI. TK1_MMIO_TK1_CDI_LAST = TK1_MMIO_TK1_BASE | 0x9c, // Address of last 32-bit word of CDI.

View File

@ -0,0 +1,15 @@
#!/bin/sh
set -eu
cd "${0%/*}"
cd ../../boards/mta1-usb-v1/test
if [ ! -e venv ]; then
python3 -m venv venv
. ./venv/bin/activate
pip3 install -r requirements.txt
else
. ./venv/bin/activate
fi
./reset.py

View File

@ -9,8 +9,11 @@ USB_VID = 0xcafe
class ice40_flasher: class ice40_flasher:
def __init__(self): def __init__(self):
self.dev = None
for dict in hid.enumerate(USB_VID): for dict in hid.enumerate(USB_VID):
self.dev = hid.Device(dict['vendor_id'], dict['product_id']) self.dev = hid.Device(dict['vendor_id'], dict['product_id'])
if self.dev is None:
raise IOError("Couldn't find any hid device with vendor id 0x%x" % (USB_VID))
def close(self): def close(self):
self.dev.close() self.dev.close()

View File

@ -0,0 +1,4 @@
hid==1.0.5
numpy==1.23.4
pyserial==3.5
pyusb==1.2.1

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
import hid_test
import time
def reset_tk1():
"""Manipulate the GPIO lines on the MTA1-USB-CH552 Programmer to issue a
hardware reset to the TK1. The result is that TK1 again will be in firmware
mode, so a new app can be loaded."""
d = hid_test.ice40_flasher()
d.gpio_set_direction(14, True)
d.gpio_put(14, False)
d.gpio_set_direction(14, False)
d.close()
reset_tk1()