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
|
*.net
|
||||||
*.dsn
|
*.dsn
|
||||||
*.ses
|
*.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
|
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*
|
||||||
|
@ -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
|
||||||
|
@ -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 |
|
||||||
|
|
||||||
|
@ -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;"
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
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:
|
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()
|
||||||
|
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