diff --git a/hw/application_fpga/fw/reset_test/Makefile b/hw/application_fpga/fw/reset_test/Makefile new file mode 100644 index 0000000..401e790 --- /dev/null +++ b/hw/application_fpga/fw/reset_test/Makefile @@ -0,0 +1,77 @@ +P := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +LIBDIR ?= ../../tkey-libs +OBJCOPY ?= llvm-objcopy +CC = clang +CFLAGS = \ + -target riscv32-unknown-none-elf \ + -march=rv32iczmmul \ + -mabi=ilp32 \ + -mcmodel=medany \ + -static \ + -std=gnu99 \ + -O2 \ + -ffast-math \ + -fno-common \ + -fno-builtin-printf \ + -fno-builtin-putchar \ + -fno-builtin-memcpy \ + -nostdlib \ + -mno-relax \ + -Wall \ + -Wpedantic \ + -Wno-language-extension-token \ + -Werror \ + -flto \ + -g \ + -I $(LIBDIR)/include \ + -I $(LIBDIR) \ + -DTKEY_DEBUG + +AS = clang + +ASFLAGS = \ + -target riscv32-unknown-none-elf \ + -march=rv32iczmmul \ + -mabi=ilp32 \ + -mno-relax + +LDFLAGS = \ + -T $(P)/app.lds \ + -L $(LIBDIR) -lcommon + +.PHONY: all +all: reset_test.bin + +# Turn elf into bin for device +%.bin: %.elf + $(OBJCOPY) --input-target=elf32-littleriscv --output-target=binary $^ $@ + chmod a-x $@ + +.PHONY: tkey-libs +tkey-libs: + make -C $(LIBDIR) + +RESET_TEST_FMTFILES = \ + $(P)/main.c \ + $(P)/syscall.h + +RESET_TEST_OBJS = \ + $(P)/main.o \ + $(P)/crt0.o \ + $(P)/syscall.o + +reset_test.elf: tkey-libs $(RESET_TEST_OBJS) + $(CC) $(CFLAGS) $(RESET_TEST_OBJS) $(LDFLAGS) -o $@ + +.PHONY: fmt +fmt: + clang-format --dry-run --ferror-limit=0 $(RESET_TEST_FMTFILES) + clang-format --verbose -i $(RESET_TEST_FMTFILES) + +.PHONY: checkfmt +checkfmt: + clang-format --dry-run --ferror-limit=0 --Werror $(RESET_TEST_FMTFILES) + +.PHONY: clean +clean: + rm -f reset_test.bin reset_test.elf $(RESET_TEST_OBJS) diff --git a/hw/application_fpga/fw/reset_test/app.lds b/hw/application_fpga/fw/reset_test/app.lds new file mode 100644 index 0000000..421122c --- /dev/null +++ b/hw/application_fpga/fw/reset_test/app.lds @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2022 Tillitis AB + * SPDX-License-Identifier: BSD-2-Clause + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + RAM (rwx) : ORIGIN = 0x40000000, LENGTH = 0x20000 /* 128 KB */ +} + +SECTIONS +{ + .text.init : + { + *(.text.init) + } >RAM + + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + *(.srodata) /* .rodata sections (constants, strings, etc.) */ + *(.srodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + _etext = .; + _sidata = _etext; + } >RAM + + .data : AT (_etext) + { + . = ALIGN(4); + _sdata = .; + . = ALIGN(4); + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.sdata) /* .sdata sections */ + *(.sdata*) /* .sdata* sections */ + . = ALIGN(4); + _edata = .; + } >RAM + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss) + *(.bss*) + *(.sbss) + *(.sbss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; + } >RAM + + /* libcrt0/crt0.S inits stack to start just below end of RAM */ +} diff --git a/hw/application_fpga/fw/reset_test/crt0.S b/hw/application_fpga/fw/reset_test/crt0.S new file mode 100644 index 0000000..f484b7d --- /dev/null +++ b/hw/application_fpga/fw/reset_test/crt0.S @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2022 Tillitis AB +// SPDX-License-Identifier: BSD-2-Clause + + .section ".text.init" + .global _start +_start: + li x1, 0 + li x2, 0 + li x3, 0 + li x4, 0 + li x5, 0 + li x6, 0 + li x7, 0 + li x8, 0 + li x9, 0 + li x10,0 + li x11,0 + li x12,0 + li x13,0 + li x14,0 + li x15,0 + li x16,0 + li x17,0 + li x18,0 + li x19,0 + li x20,0 + li x21,0 + li x22,0 + li x23,0 + li x24,0 + li x25,0 + li x26,0 + li x27,0 + li x28,0 + li x29,0 + li x30,0 + li x31,0 + + /* init stack below 0x40020000 (TK1_RAM_BASE+TK1_RAM_SIZE) */ + li sp, 0x4001fff0 + + /* zero-init bss section */ + la a0, _sbss + la a1, _ebss + bge a0, a1, end_init_bss + +loop_init_bss: + sw zero, 0(a0) + addi a0, a0, 4 + blt a0, a1, loop_init_bss + +end_init_bss: + call main diff --git a/hw/application_fpga/fw/reset_test/main.c b/hw/application_fpga/fw/reset_test/main.c new file mode 100644 index 0000000..6e15849 --- /dev/null +++ b/hw/application_fpga/fw/reset_test/main.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2022, 2023 - Tillitis AB + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../tk1/proto.h" +#include "../tk1/syscall_num.h" +#include "../tk1/resetinfo.h" +#include "../tk1/syscall.h" +#include "../tk1/syscall_num.h" + +// Converts a single hex character to its integer value +static uint8_t hex_char_to_byte(uint8_t c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0; // Invalid character, should not happen if input is valid +} + +// Converts a 64-char hex string into a 32-byte array +int hex_string_to_bytes(uint8_t *hex_str, uint8_t *out_bytes, size_t out_len) +{ + if (!hex_str || !out_bytes || out_len < 32) + return -1; // Error handling + + for (size_t i = 0; i < 32; i++) { + out_bytes[i] = (hex_char_to_byte(hex_str[i * 2]) << 4) | hex_char_to_byte(hex_str[i * 2 + 1]); + } + + return 0; // Success +} +//--------------------------------------- + +#define BUFSIZE 32 + +int main(void) +{ + uint8_t available = 0; + uint8_t cmdbuf[BUFSIZE] = { 0 }; + enum ioend endpoint = IO_NONE; + led_set(LED_BLUE); + + while(1) { + + debug_puts("Waiting for command\n"); + + memset(cmdbuf, 0, BUFSIZE); + + // Wait for data + if (readselect(IO_TKEYCTRL, &endpoint, &available) < 0) { + assert(1 == 2); + } + + if (read(IO_TKEYCTRL, cmdbuf, BUFSIZE, available) < 0) { + // read failed! I/O broken? Just redblink. + assert(1 == 2); + } + + switch (cmdbuf[0]) { + case '1': { + syscall(TK1_SYSCALL_RESET, 0); + } + break; + + case '2': { + struct reset rst = { 0 }; + rst.type = LOAD_APP_FROM_HOST; + syscall(TK1_SYSCALL_RESET_WITH_INTENT, (uint32_t)&rst); + } + break; + + case '3': { + struct reset rst = { 0 }; + rst.type = LOAD_APP_FROM_FLASH; + syscall(TK1_SYSCALL_RESET_WITH_INTENT, (uint32_t)&rst); + } + break; + + case '4': { + struct reset rst = { 0 }; + uint8_t string[] = "83da11b65f9c3721879bc4d9cffa6eac2368dcd9562aedde4002e6108ac939b3"; + rst.type = LOAD_APP_FROM_HOST_WITH_DIGEST; + hex_string_to_bytes(string, (uint8_t *)&rst.app_digest, sizeof(rst.app_digest)); + syscall(TK1_SYSCALL_RESET_WITH_INTENT, (uint32_t)&rst); + } + break; + + case '5': { + struct reset rst = { 0 }; + uint8_t string[] = "ef1337a922945fd87683b71ed275e02af44b3489057a29d14fd78daff8b73a28"; + rst.type = LOAD_APP_FROM_HOST_WITH_DIGEST; + hex_string_to_bytes(string, (uint8_t *)&rst.app_digest, sizeof(rst.app_digest)); + syscall(TK1_SYSCALL_RESET_WITH_INTENT, (uint32_t)&rst); + } + break; + + default: { + } + break; + } + } +} diff --git a/hw/application_fpga/fw/reset_test/syscall.S b/hw/application_fpga/fw/reset_test/syscall.S new file mode 100644 index 0000000..5fc9b3f --- /dev/null +++ b/hw/application_fpga/fw/reset_test/syscall.S @@ -0,0 +1,85 @@ +// SPDX-FileCopyrightText: 2024 Tillitis AB +// SPDX-License-Identifier: BSD-2-Clause + +#include "../tk1/picorv32/custom_ops.S" + + .section ".text" + .globl syscall + + +syscall: + // Save registers to stack + addi sp, sp, -32*4 + sw x0, 0*4(sp) + sw x1, 1*4(sp) + // x2 (sp) is assumed to be preserved by the interrupt handler. + sw x3, 3*4(sp) + sw x4, 4*4(sp) + sw x5, 5*4(sp) + sw x6, 6*4(sp) + sw x7, 7*4(sp) + sw x8, 8*4(sp) + sw x9, 9*4(sp) + // x10 (a0) will contain syscall return value. And should not be saved. + sw x11, 11*4(sp) + sw x12, 12*4(sp) + sw x13, 13*4(sp) + sw x14, 14*4(sp) + sw x15, 15*4(sp) + sw x16, 16*4(sp) + sw x17, 17*4(sp) + sw x18, 18*4(sp) + sw x19, 19*4(sp) + sw x20, 20*4(sp) + sw x21, 21*4(sp) + sw x22, 22*4(sp) + sw x23, 23*4(sp) + sw x24, 24*4(sp) + sw x25, 25*4(sp) + sw x26, 26*4(sp) + sw x27, 27*4(sp) + sw x28, 28*4(sp) + sw x29, 29*4(sp) + sw x30, 30*4(sp) + sw x31, 31*4(sp) + + // Trigger syscall interrupt + li t1, 0xe1000000 // Syscall interrupt trigger address + sw zero, 0(t1) // Trigger interrupt + + // Restore registers from stack + lw x0, 0*4(sp) + lw x1, 1*4(sp) + // x2 (sp) is assumed to be preserved by the interrupt handler. + lw x3, 3*4(sp) + lw x4, 4*4(sp) + lw x5, 5*4(sp) + lw x6, 6*4(sp) + lw x7, 7*4(sp) + lw x8, 8*4(sp) + lw x9, 9*4(sp) + // x10 (a0) contains syscall return value. And should not be destroyed. + lw x11, 11*4(sp) + lw x12, 12*4(sp) + lw x13, 13*4(sp) + lw x14, 14*4(sp) + lw x15, 15*4(sp) + lw x16, 16*4(sp) + lw x17, 17*4(sp) + lw x18, 18*4(sp) + lw x19, 19*4(sp) + lw x20, 20*4(sp) + lw x21, 21*4(sp) + lw x22, 22*4(sp) + lw x23, 23*4(sp) + lw x24, 24*4(sp) + lw x25, 25*4(sp) + lw x26, 26*4(sp) + lw x27, 27*4(sp) + lw x28, 28*4(sp) + lw x29, 29*4(sp) + lw x30, 30*4(sp) + lw x31, 31*4(sp) + addi sp, sp, 32*4 + + ret diff --git a/hw/application_fpga/fw/tk1/main.c b/hw/application_fpga/fw/tk1/main.c index 62e496c..70d2fe6 100644 --- a/hw/application_fpga/fw/tk1/main.c +++ b/hw/application_fpga/fw/tk1/main.c @@ -15,6 +15,7 @@ #include "proto.h" #include "state.h" #include "syscall_enable.h" +#include "resetinfo.h" // clang-format off static volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST; @@ -33,8 +34,11 @@ static volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER static volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL; static volatile uint32_t *ram_addr_rand = (volatile uint32_t *)TK1_MMIO_TK1_RAM_ADDR_RAND; static volatile uint32_t *ram_data_rand = (volatile uint32_t *)TK1_MMIO_TK1_RAM_DATA_RAND; +static volatile uint8_t *resetinfo = (volatile uint8_t *)TK1_MMIO_RESETINFO_BASE; // clang-format on +#define RESETINFO ((struct reset *)TK1_MMIO_RESETINFO_BASE) + // Context for the loading of a TKey program struct context { uint32_t left; // Bytes left to receive @@ -406,6 +410,32 @@ int main(void) uint8_t cmd[CMDSIZE] = {0}; enum state state = FW_STATE_INITIAL; + if (RESETINFO->type != UNKNOWN) { + debug_puts("\nTKEY was reset!\n"); + debug_puts("Reset type = "); + debug_putinthex(RESETINFO->type); + debug_lf(); + switch(RESETINFO->type) { + case LOAD_APP_FROM_HOST_WITH_DIGEST: + debug_puts("App Digest = "); + for(uint8_t i = 0; i<32; i++) { + debug_puthex(RESETINFO->app_digest[i]); + } + debug_lf(); + break; + case LOAD_APP_FROM_FLASH_WITH_DIGEST: + debug_puts("App Digest = "); + for(uint8_t i = 0; i<32; i++) { + debug_puthex(RESETINFO->app_digest[i]); + } + debug_lf(); + break; + } + + // Clear resetinfo area + memset((uint8_t *)resetinfo, 0, TK1_MMIO_RESETINFO_SIZE); + } + print_hw_version(); /*@-mustfreeonly@*/ diff --git a/hw/application_fpga/fw/tk1/resetinfo.h b/hw/application_fpga/fw/tk1/resetinfo.h new file mode 100644 index 0000000..0e27c41 --- /dev/null +++ b/hw/application_fpga/fw/tk1/resetinfo.h @@ -0,0 +1,22 @@ +// Copyright (C) 2025 - Tillitis AB +// SPDX-License-Identifier: GPL-2.0-only + +#ifndef TKEY_RESETINFO_H +#define TKEY_RESETINFO_H + +#include + +enum reset_type_num { + UNKNOWN = 0, + LOAD_APP_FROM_HOST = 1, + LOAD_APP_FROM_FLASH = 2, + LOAD_APP_FROM_HOST_WITH_DIGEST = 3, + LOAD_APP_FROM_FLASH_WITH_DIGEST = 4, +}; + +struct reset { + uint32_t type; // Reset type + uint8_t app_digest[32]; // Program digest +}; + +#endif diff --git a/hw/application_fpga/fw/tk1/syscall.h b/hw/application_fpga/fw/tk1/syscall.h new file mode 100644 index 0000000..9ddd1dd --- /dev/null +++ b/hw/application_fpga/fw/tk1/syscall.h @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2024 Tillitis AB +// SPDX-License-Identifier: BSD-2-Clause + +#ifndef TKEY_APP_SYSCALL_H +#define TKEY_APP_SYSCALL_H + +#include + +int syscall(uint32_t number, uint32_t arg1); + +#endif diff --git a/hw/application_fpga/fw/tk1/syscall_handler.c b/hw/application_fpga/fw/tk1/syscall_handler.c index 0d26fa8..4c61473 100644 --- a/hw/application_fpga/fw/tk1/syscall_handler.c +++ b/hw/application_fpga/fw/tk1/syscall_handler.c @@ -6,12 +6,14 @@ #include #include #include - +#include +#include "../tk1/resetinfo.h" #include "../tk1/syscall_num.h" // clang-format off static volatile uint32_t *system_reset = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_RESET; static volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST; +static volatile uint8_t *resetinfo = (volatile uint8_t *)TK1_MMIO_RESETINFO_BASE; // clang-format on int32_t syscall_handler(uint32_t number, uint32_t arg1) @@ -20,6 +22,10 @@ int32_t syscall_handler(uint32_t number, uint32_t arg1) case TK1_SYSCALL_RESET: *system_reset = 1; return 0; + case TK1_SYSCALL_RESET_WITH_INTENT: + memcpy((uint8_t *)resetinfo, (uint8_t *)arg1, sizeof(struct reset)); + *system_reset = 1; + return 0; case TK1_SYSCALL_SET_LED: led_set(arg1); return 0; diff --git a/hw/application_fpga/fw/tk1/syscall_num.h b/hw/application_fpga/fw/tk1/syscall_num.h index 82f3f06..08d43ae 100644 --- a/hw/application_fpga/fw/tk1/syscall_num.h +++ b/hw/application_fpga/fw/tk1/syscall_num.h @@ -6,6 +6,7 @@ enum syscall_num { TK1_SYSCALL_RESET = 1, + TK1_SYSCALL_RESET_WITH_INTENT = 2, TK1_SYSCALL_SET_LED = 10, TK1_SYSCALL_GET_VIDPID = 12, }; diff --git a/hw/application_fpga/tkey-libs/include/tkey/tk1_mem.h b/hw/application_fpga/tkey-libs/include/tkey/tk1_mem.h index 53b82e9..3facc53 100644 --- a/hw/application_fpga/tkey-libs/include/tkey/tk1_mem.h +++ b/hw/application_fpga/tkey-libs/include/tkey/tk1_mem.h @@ -69,6 +69,9 @@ // FW_RAM is 4096 bytes #define TK1_MMIO_FW_RAM_SIZE 0x1000 +#define TK1_MMIO_RESETINFO_BASE 0xd0000f00 +#define TK1_MMIO_RESETINFO_SIZE 0x100 + #define TK1_MMIO_TRNG_BASE 0xc0000000 #define TK1_MMIO_TRNG_STATUS 0xc0000024 #define TK1_MMIO_TRNG_STATUS_READY_BIT 0