diff --git a/doc/system_description/software.md b/doc/system_description/software.md index be4b301..7f46270 100644 --- a/doc/system_description/software.md +++ b/doc/system_description/software.md @@ -418,6 +418,35 @@ host <- RSP[36..] = 0 ``` +### Firmware services + +The firmware exposes a BLAKE2s function through a function pointer +located in MMIO `BLAKE2S` (see memory map below) with the with +function signature: + +```c +int blake2s(void *out, unsigned long outlen, const void *key, + unsigned long keylen, const void *in, unsigned long inlen, + blake2s_ctx *ctx); + +``` + +where `blake2s_ctx` is: + +```c +typedef struct { + uint8_t b[64]; // input buffer + uint32_t h[8]; // chained state + uint32_t t[2]; // total number of bytes + size_t c; // pointer for b[] + size_t outlen; // digest size +} blake2s_ctx; +``` + +The `libcommon` library in +[tillitis-key1-apps](https://github.com/tillitis/tillitis-key1-apps/) +has a wrapper for using this function. + ## Memory map Assigned top level prefixes: @@ -463,40 +492,41 @@ Assigned core prefixes: *Nota bene*: MMIO accesses should be 32 bit wide, e.g use `lw` and `sw`. Exceptions are `FW_RAM` and `QEMU_DEBUG`. -| *name* | *fw* | *app* | *size* | *type* | *content* | *description* | -|-------------------|-------|-----------|--------|----------|-----------|------------------------------------------------------------------------| -| `TRNG_STATUS` | r | r | | | | TRNG_STATUS_READY_BIT is 1 when an entropy word is available. | -| `TRNG_ENTROPY` | r | r | 4B | u32 | | Entropy word. Reading a word will clear status. | -| `TIMER_CTRL` | r/w | r/w | | | | If TIMER_STATUS_READY_BIT in TIMER_STATUS is 1, writing anything here | -| | | | | | | starts the timer. If the same bit is 0 then writing stops the timer. | -| `TIMER_STATUS` | r | r | | | | TIMER_STATUS_READY_BIT is 1 when timer is ready to start running. | -| `TIMER_PRESCALER` | r/w | r/w | 4B | | | Prescaler init value. Write blocked when running. | -| `TIMER_TIMER` | r/w | r/w | 4B | | | Timer init or current value while running. Write blocked when running. | -| `UDS_FIRST` | r[^3] | invisible | 4B | u8[32] | | First word of Unique Device Secret key. | -| `UDS_LAST` | | invisible | | | | The last word of the UDS | -| `UART_BITRATE` | r/w | | | | | TBD | -| `UART_DATABITS` | r/w | | | | | TBD | -| `UART_STOPBITS` | r/w | | | | | TBD | -| `UART_RX_STATUS` | r | r | 1B | u8 | | Non-zero when there is data to read | -| `UART_RX_DATA` | r | r | 1B | u8 | | Data to read. Only LSB contains data | -| `UART_TX_STATUS` | r | r | 1B | u8 | | Non-zero when it's OK to write data | -| `UART_TX_DATA` | w | w | 1B | u8 | | Data to send. Only LSB contains data | -| `TOUCH_STATUS` | r/w | r/w | | | | TOUCH_STATUS_EVENT_BIT is 1 when touched. After detecting a touch | -| | | | | | | event (reading a 1), write anything here to acknowledge it. | -| `FW_RAM` | r/w | invisible | 1 kiB | u8[1024] | | Firmware-only RAM. | -| `UDA` | r | invisible | 16B | u8[16] | | Unique Device Authentication key. | -| `UDI` | r | r | 8B | u64 | | Unique Device ID (UDI). | -| `QEMU_DEBUG` | w | w | | u8 | | Debug console (only in QEMU) | -| `NAME0` | r | r | 4B | char[4] | "tk1 " | ID of core/stick | -| `NAME1` | r | r | 4B | char[4] | "mkdf" | ID of core/stick | -| `VERSION` | r | r | 4B | u32 | 1 | Current version. | -| `SWITCH_APP` | r/w | r | 1B | u8 | | Write anything here to trigger the switch to application mode. Reading | -| | | | | | | 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 | | 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 | +| *name* | *fw* | *app* | *size* | *type* | *content* | *description* | +|-------------------|-------|-----------|--------|----------|-----------|-------------------------------------------------------------------------| +| `TRNG_STATUS` | r | r | | | | TRNG_STATUS_READY_BIT is 1 when an entropy word is available. | +| `TRNG_ENTROPY` | r | r | 4B | u32 | | Entropy word. Reading a word will clear status. | +| `TIMER_CTRL` | r/w | r/w | | | | If TIMER_STATUS_READY_BIT in TIMER_STATUS is 1, writing anything here | +| | | | | | | starts the timer. If the same bit is 0 then writing stops the timer. | +| `TIMER_STATUS` | r | r | | | | TIMER_STATUS_READY_BIT is 1 when timer is ready to start running. | +| `TIMER_PRESCALER` | r/w | r/w | 4B | | | Prescaler init value. Write blocked when running. | +| `TIMER_TIMER` | r/w | r/w | 4B | | | Timer init or current value while running. Write blocked when running. | +| `UDS_FIRST` | r[^3] | invisible | 4B | u8[32] | | First word of Unique Device Secret key. | +| `UDS_LAST` | | invisible | | | | The last word of the UDS | +| `UART_BITRATE` | r/w | | | | | TBD | +| `UART_DATABITS` | r/w | | | | | TBD | +| `UART_STOPBITS` | r/w | | | | | TBD | +| `UART_RX_STATUS` | r | r | 1B | u8 | | Non-zero when there is data to read | +| `UART_RX_DATA` | r | r | 1B | u8 | | Data to read. Only LSB contains data | +| `UART_TX_STATUS` | r | r | 1B | u8 | | Non-zero when it's OK to write data | +| `UART_TX_DATA` | w | w | 1B | u8 | | Data to send. Only LSB contains data | +| `TOUCH_STATUS` | r/w | r/w | | | | TOUCH_STATUS_EVENT_BIT is 1 when touched. After detecting a touch | +| | | | | | | event (reading a 1), write anything here to acknowledge it. | +| `FW_RAM` | r/w | invisible | 1 kiB | u8[1024] | | Firmware-only RAM. | +| `UDA` | r | invisible | 16B | u8[16] | | Unique Device Authentication key. | +| `UDI` | r | r | 8B | u64 | | Unique Device ID (UDI). | +| `QEMU_DEBUG` | w | w | | u8 | | Debug console (only in QEMU) | +| `NAME0` | r | r | 4B | char[4] | "tk1 " | ID of core/stick | +| `NAME1` | r | r | 4B | char[4] | "mkdf" | ID of core/stick | +| `VERSION` | r | r | 4B | u32 | 1 | Current version. | +| `SWITCH_APP` | r/w | r | 1B | u8 | | Write anything here to trigger the switch to application mode. Reading | +| | | | | | | 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 | | 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 | +| `BLAKE2S` | r/w | r | 4B | u32 | | Function pointer to a BLAKE2S function in the firmware | +| `CDI_FIRST` | r/w | r | 32B | u8[32] | | Compound Device Identifier (CDI). UDS+measurement... | +| `CDI_LAST` | | r | | | | Last word of CDI | [^3]: The UDS can only be read *once* per power-cycle. diff --git a/hw/application_fpga/Makefile b/hw/application_fpga/Makefile index 0ea5826..e666bf7 100644 --- a/hw/application_fpga/Makefile +++ b/hw/application_fpga/Makefile @@ -84,7 +84,8 @@ TESTFW_OBJS = \ $(P)/fw/testfw/main.o \ $(P)/fw/tk1/start.o \ $(P)/fw/tk1/proto.o \ - $(P)/fw/tk1/lib.o + $(P)/fw/tk1/lib.o \ + $(P)/fw/tk1/blake2s/blake2s.o #------------------------------------------------------------------- # All: Complete build of HW and FW. diff --git a/hw/application_fpga/fw/testfw/main.c b/hw/application_fpga/fw/testfw/main.c index 366acb4..4a623fe 100644 --- a/hw/application_fpga/fw/testfw/main.c +++ b/hw/application_fpga/fw/testfw/main.c @@ -3,26 +3,31 @@ * SPDX-License-Identifier: GPL-2.0-only */ +#include "../tk1/blake2s/blake2s.h" #include "../tk1/lib.h" #include "../tk1/proto.h" #include "../tk1/types.h" #include "../tk1_mem.h" // clang-format off -volatile uint32_t *tk1name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0; -volatile uint32_t *tk1name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1; -volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST; -volatile uint32_t *uda = (volatile uint32_t *)TK1_MMIO_QEMU_UDA; // Only in QEMU right now -volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST; -volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST; -volatile uint32_t *switch_app = (volatile uint32_t *)TK1_MMIO_TK1_SWITCH_APP; -volatile uint8_t *fw_ram = (volatile uint8_t *)TK1_MMIO_FW_RAM_BASE; -volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER; +volatile uint32_t *tk1name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0; +volatile uint32_t *tk1name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1; +volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST; +volatile uint32_t *uda = (volatile uint32_t *)TK1_MMIO_QEMU_UDA; // Only in QEMU right now +volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST; +volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST; +volatile uint32_t *switch_app = (volatile uint32_t *)TK1_MMIO_TK1_SWITCH_APP; +volatile uint8_t *fw_ram = (volatile uint8_t *)TK1_MMIO_FW_RAM_BASE; +volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER; volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER; -volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS; -volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL; -volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS; -volatile uint32_t *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY; +volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS; +volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL; +volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS; +volatile uint32_t *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY; +volatile uint32_t *fw_blake2s_addr = (volatile uint32_t *)TK1_MMIO_TK1_BLAKE2S; + +// Function pointer to blake2s() +volatile int (*fw_blake2s)(void *, unsigned long, const void *, unsigned long, const void *, unsigned long, blake2s_ctx *); // clang-format on // TODO Real UDA is 4 words (16 bytes) @@ -57,6 +62,23 @@ void puthexn(uint8_t *p, int n) } } +void hexdump(uint8_t *buf, int len) +{ + uint8_t *row; + uint8_t *byte; + uint8_t *max; + + row = buf; + max = &buf[len]; + for (byte = 0; byte != max; row = byte) { + for (byte = row; byte != max && byte != (row + 16); byte++) { + puthex(*byte); + } + + puts("\r\n"); + } +} + void reverseword(uint32_t *wordp) { *wordp = ((*wordp & 0xff000000) >> 24) | ((*wordp & 0x00ff0000) >> 8) | @@ -157,6 +179,9 @@ int main() anyfailed = 1; } + // Store function pointer to blake2s() so it's reachable from app + *fw_blake2s_addr = (uint32_t)blake2s; + // Turn on application mode. // ------------------------- *switch_app = 1; @@ -238,6 +263,32 @@ int main() anyfailed = 1; } + // Testing the blake2s MMIO in app mode + + fw_blake2s = (volatile int (*)(void *, unsigned long, const void *, + unsigned long, const void *, + unsigned long, blake2s_ctx *)) * + fw_blake2s_addr; + + char msg[17] = "dldlkjsdkljdslsdj"; + uint32_t digest0[8]; + uint32_t digest1[8]; + blake2s_ctx b2s_ctx; + + blake2s(&digest0[0], 32, NULL, 0, &msg, 17, &b2s_ctx); + fw_blake2s(&digest1[0], 32, NULL, 0, &msg, 17, &b2s_ctx); + + puts("digest #0: \r\n"); + hexdump((uint8_t *)digest0, 32); + + puts("digest #1: \r\n"); + hexdump((uint8_t *)digest1, 32); + + if (!memeq(digest0, digest1, 32)) { + puts("FAIL: Digests not the same\r\n"); + anyfailed = 1; + } + // Check and display test results. if (anyfailed) { puts("Some test FAILED!\r\n"); diff --git a/hw/application_fpga/fw/tk1/main.c b/hw/application_fpga/fw/tk1/main.c index 99e2cb2..ccd53cc 100644 --- a/hw/application_fpga/fw/tk1/main.c +++ b/hw/application_fpga/fw/tk1/main.c @@ -10,17 +10,18 @@ #include "types.h" // 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; -static volatile uint32_t *name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0; -static volatile uint32_t *name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1; -static volatile uint32_t *ver = (volatile uint32_t *)TK1_MMIO_TK1_VERSION; -static volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST; -static volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST; -static volatile uint32_t *app_addr = (volatile uint32_t *)TK1_MMIO_TK1_APP_ADDR; -static volatile uint32_t *app_size = (volatile uint32_t *)TK1_MMIO_TK1_APP_SIZE; -static volatile uint8_t *fw_ram = (volatile uint8_t *)TK1_MMIO_FW_RAM_BASE; -static volatile uint32_t *led = (volatile uint32_t *)TK1_MMIO_TK1_LED; +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 *name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0; +static volatile uint32_t *name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1; +static volatile uint32_t *ver = (volatile uint32_t *)TK1_MMIO_TK1_VERSION; +static volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST; +static volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST; +static volatile uint32_t *app_addr = (volatile uint32_t *)TK1_MMIO_TK1_APP_ADDR; +static volatile uint32_t *app_size = (volatile uint32_t *)TK1_MMIO_TK1_APP_SIZE; +static volatile uint8_t *fw_ram = (volatile uint8_t *)TK1_MMIO_FW_RAM_BASE; +static volatile uint32_t *led = (volatile uint32_t *)TK1_MMIO_TK1_LED; +static volatile uint32_t *fw_blake2s_addr = (volatile uint32_t *)TK1_MMIO_TK1_BLAKE2S; #define LED_RED (1 << TK1_MMIO_TK1_LED_R_BIT) #define LED_GREEN (1 << TK1_MMIO_TK1_LED_G_BIT) @@ -149,6 +150,8 @@ int main() uint8_t uss[32] = {0}; uint8_t digest[32] = {0}; enum state state = FW_STATE_INITIAL; + // Let the app know the function adddress for blake2s() + *fw_blake2s_addr = (uint32_t)blake2s; print_hw_version(namever); diff --git a/hw/application_fpga/fw/tk1_mem.h b/hw/application_fpga/fw/tk1_mem.h index dcd341b..3e10e32f 100644 --- a/hw/application_fpga/fw/tk1_mem.h +++ b/hw/application_fpga/fw/tk1_mem.h @@ -87,6 +87,7 @@ enum { TK1_MMIO_TK1_GPIO4_BIT = 3, TK1_MMIO_TK1_APP_ADDR = TK1_MMIO_TK1_BASE | 0x30, TK1_MMIO_TK1_APP_SIZE = TK1_MMIO_TK1_BASE | 0x34, + TK1_MMIO_TK1_BLAKE2S = TK1_MMIO_TK1_BASE | 0x40, 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_UDI_FIRST = TK1_MMIO_TK1_BASE | 0xc0,