mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2024-10-01 01:45:38 -04:00
Merge branch 'main' of github.com:tillitis/tillitis-key1
This commit is contained in:
commit
1a49304224
2
.gitignore
vendored
2
.gitignore
vendored
@ -64,3 +64,5 @@ fp-info-cache
|
||||
*.net
|
||||
*.dsn
|
||||
*.ses
|
||||
|
||||
__pycache__
|
||||
|
@ -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
|
||||
ensuring that each app loaded will have its own cryptographic
|
||||
identity. The design is similar to TCG DICE. The Tillitis Key 1
|
||||
platform has 128 KB of RAM. The current firmware design allows for
|
||||
applications up to 64 KB with a 64 KB stack.
|
||||
platform has 128 KB of RAM. The current firmware is designed to load
|
||||
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*
|
||||
|
@ -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
|
||||
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
|
||||
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
|
||||
Blinkinlabs ICE40 programmer`. If the USB stick is also connected it
|
||||
|
@ -63,7 +63,9 @@ between the host and the device.
|
||||
## Firmware
|
||||
|
||||
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
|
||||
`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
|
||||
`_start` from `start.S` which initializes the `.data`, and `.bss` 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
|
||||
the `UART_RX_{STATUS,DATA}` registers. When a complete command is
|
||||
read, the firmware executes the command.
|
||||
@ -81,7 +83,7 @@ read, the firmware executes the command.
|
||||
### Loading an application
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
full application.
|
||||
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
|
||||
each received block.
|
||||
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 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,
|
||||
completing the loading.
|
||||
|
||||
@ -355,8 +357,8 @@ Assigned core prefixes:
|
||||
| | | | | | | returns 0 if device is in firmware mode, 0xffffffff if in app mode. |
|
||||
| `LED` | w | w | 1B | u8 | | |
|
||||
| `GPIO` | | | | | | |
|
||||
| `APP_ADDR` | r/w | r | 4B | u32 | | Application address (0x4000_0000) |
|
||||
| `APP_SIZE` | r/w | r | 4B | u32 | | Application size |
|
||||
| `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 | | 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_LAST` | | r | | | | Last word of CDI |
|
||||
|
||||
|
@ -9,10 +9,6 @@
|
||||
#include "proto.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
|
||||
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;
|
||||
@ -95,7 +91,7 @@ int main()
|
||||
struct frame_header hdr; // Used in both directions
|
||||
uint8_t cmd[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
|
||||
uint8_t uss[32] = {0};
|
||||
uint8_t digest[32] = {0};
|
||||
@ -177,7 +173,7 @@ int main()
|
||||
putinthex(local_app_size);
|
||||
lf();
|
||||
|
||||
if (local_app_size > APP_MAX_SIZE) {
|
||||
if (local_app_size > TK1_APP_MAX_SIZE) {
|
||||
rsp[0] = STATUS_BAD;
|
||||
fwreply(hdr, FW_RSP_LOAD_APP_SIZE, rsp);
|
||||
break;
|
||||
@ -190,7 +186,7 @@ int main()
|
||||
memset(digest, 0, 32);
|
||||
|
||||
// Reset where to start loading the program
|
||||
loadaddr = (uint8_t *)APP_RAM_ADDR;
|
||||
loadaddr = (uint8_t *)TK1_APP_ADDR;
|
||||
left = *app_size;
|
||||
|
||||
rsp[0] = STATUS_OK;
|
||||
@ -224,7 +220,7 @@ int main()
|
||||
putinthex(*app_size);
|
||||
lf();
|
||||
|
||||
*app_addr = APP_RAM_ADDR;
|
||||
*app_addr = TK1_APP_ADDR;
|
||||
// Get the Blake2S digest of the app - store it
|
||||
// for later queries
|
||||
blake2s_ctx ctx;
|
||||
@ -266,8 +262,9 @@ int main()
|
||||
lf();
|
||||
// clang-format off
|
||||
asm volatile(
|
||||
// Clear the stack
|
||||
"li a0, 0x40000000;" // TK1_RAM_BASE
|
||||
"li a1, 0x40010000;"
|
||||
"li a1, 0x40007000;" // APP_RAM_ADDR
|
||||
"loop:;"
|
||||
"sw zero, 0(a0);"
|
||||
"addi a0, a0, 4;"
|
||||
|
@ -39,15 +39,15 @@ _start:
|
||||
li x31,0
|
||||
|
||||
/* Clear all RAM */
|
||||
li a0, 0x40000000 // RAM base
|
||||
li a1, 0x40020000 // To end of SRAM
|
||||
li a0, 0x40000000 // TK1_RAM_BASE
|
||||
li a1, 0x40020000 // TK1_RAM_BASE + TK1_RAM_SIZE
|
||||
clear:
|
||||
sw zero, 0(a0)
|
||||
addi a0, a0, 4
|
||||
blt a0, a1, clear
|
||||
|
||||
/* init stack to right under where we load app at 0x40010000 */
|
||||
li sp, 0x4000fff0
|
||||
/* init stack below 0x40007000 (TK1_APP_ADDR) where we load app */
|
||||
li sp, 0x40006ff0
|
||||
|
||||
/* copy data section */
|
||||
la a0, _sidata
|
||||
|
@ -20,10 +20,14 @@
|
||||
enum {
|
||||
TK1_ROM_BASE = 0x00000000, // 0b00000000...
|
||||
TK1_RAM_BASE = 0x40000000, // 0b01000000...
|
||||
TK1_RAM_SIZE = 0x20000, // 128 KB
|
||||
TK1_RESERVED_BASE = 0x80000000, // 0b10000000...
|
||||
TK1_MMIO_BASE = 0xc0000000, // 0b11000000...
|
||||
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_TIMER_BASE = TK1_MMIO_BASE | 0x01000000,
|
||||
TK1_MMIO_UDS_BASE = TK1_MMIO_BASE | 0x02000000,
|
||||
@ -81,7 +85,7 @@ enum {
|
||||
TK1_MMIO_TK1_GPIO2_BIT = 1,
|
||||
TK1_MMIO_TK1_GPIO3_BIT = 2,
|
||||
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_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.
|
||||
|
15
hw/application_fpga/tools/reset-tk1
Executable file
15
hw/application_fpga/tools/reset-tk1
Executable 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
|
@ -9,8 +9,11 @@ USB_VID = 0xcafe
|
||||
|
||||
class ice40_flasher:
|
||||
def __init__(self):
|
||||
self.dev = None
|
||||
for dict in hid.enumerate(USB_VID):
|
||||
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):
|
||||
self.dev.close()
|
||||
|
4
hw/boards/mta1-usb-v1/test/requirements.txt
Normal file
4
hw/boards/mta1-usb-v1/test/requirements.txt
Normal file
@ -0,0 +1,4 @@
|
||||
hid==1.0.5
|
||||
numpy==1.23.4
|
||||
pyserial==3.5
|
||||
pyusb==1.2.1
|
16
hw/boards/mta1-usb-v1/test/reset.py
Executable file
16
hw/boards/mta1-usb-v1/test/reset.py
Executable 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()
|
Loading…
Reference in New Issue
Block a user