mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-08-17 19:02:15 -04:00
fw: Add pre loaded flash app and flash data storage
- Add per app flash storage - Adds four data areas. An app can allocate an area. Once allocated the area is tied to the CDI of the app and can only be read/written/deallocated by the same app. - Add two pre loaded app slots to flash - Load an app from the first slot at boot. The app digest must match a specific digest specified in firmware. - Optionally load an app from the second slot - Add a resetinfo area in FW_RAM which is used to signal an app's intent of resetting the system and, optionally, pass data to firmware or the next app in a bootchain. Co-authored-by: Jonas Thörnblad <jonas@tillitis.se> Co-authored-by: Mikael Ågren <mikael@tillitis.se> Co-authored-by: Daniel Jobson <jobson@tillitis.se>
This commit is contained in:
parent
4841b1b127
commit
2c1c05f180
25 changed files with 1642 additions and 27 deletions
|
@ -3,16 +3,21 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include <blake2s/blake2s.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <tkey/assert.h>
|
||||
#include <tkey/debug.h>
|
||||
#include <tkey/led.h>
|
||||
#include <tkey/lib.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
|
||||
#include "blake2s/blake2s.h"
|
||||
#include "mgmt_app.h"
|
||||
#include "partition_table.h"
|
||||
#include "preload_app.h"
|
||||
#include "proto.h"
|
||||
#include "resetinfo.h"
|
||||
#include "state.h"
|
||||
#include "syscall_enable.h"
|
||||
|
||||
|
@ -33,8 +38,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 struct reset *resetinfo = (volatile struct reset *)TK1_MMIO_RESETINFO_BASE;
|
||||
// clang-format on
|
||||
|
||||
struct partition_table_storage part_table_storage;
|
||||
|
||||
// Context for the loading of a TKey program
|
||||
struct context {
|
||||
uint32_t left; // Bytes left to receive
|
||||
|
@ -42,6 +50,9 @@ struct context {
|
|||
uint8_t *loadaddr; // Where we are currently loading a TKey program
|
||||
bool use_uss; // Use USS?
|
||||
uint8_t uss[32]; // User Supplied Secret, if any
|
||||
uint8_t flash_slot; // App is loaded from flash slot number
|
||||
/*@null@*/ volatile uint8_t
|
||||
*ver_digest; // Verify loaded app against this digest
|
||||
};
|
||||
|
||||
static void print_hw_version(void);
|
||||
|
@ -56,11 +67,14 @@ static enum state initial_commands(const struct frame_header *hdr,
|
|||
static enum state loading_commands(const struct frame_header *hdr,
|
||||
const uint8_t *cmd, enum state state,
|
||||
struct context *ctx);
|
||||
static void run(const struct context *ctx);
|
||||
#if !defined(SIMULATION)
|
||||
static uint32_t xorwow(uint32_t state, uint32_t acc);
|
||||
#endif
|
||||
static void scramble_ram(void);
|
||||
static int compute_app_digest(uint8_t *digest);
|
||||
static int load_flash_app(struct partition_table *part_table,
|
||||
uint8_t digest[32], uint8_t slot);
|
||||
static enum state start_where(struct context *ctx);
|
||||
|
||||
static void print_hw_version(void)
|
||||
{
|
||||
|
@ -80,6 +94,7 @@ static void print_digest(uint8_t *md)
|
|||
for (int j = 0; j < 4; j++) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
debug_puthex(md[i + 8 * j]);
|
||||
(void)md;
|
||||
}
|
||||
debug_lf();
|
||||
}
|
||||
|
@ -144,6 +159,7 @@ static void compute_cdi(const uint8_t *digest, const uint8_t use_uss,
|
|||
static void copy_name(uint8_t *buf, const size_t bufsiz, const uint32_t word)
|
||||
{
|
||||
assert(bufsiz >= 4);
|
||||
assert(buf != NULL);
|
||||
|
||||
buf[0] = word >> 24;
|
||||
buf[1] = word >> 16;
|
||||
|
@ -287,9 +303,7 @@ static enum state loading_commands(const struct frame_header *hdr,
|
|||
|
||||
// Compute Blake2S digest of the app,
|
||||
// storing it for FW_STATE_RUN
|
||||
blake2err =
|
||||
blake2s(&ctx->digest, 32, NULL, 0,
|
||||
(const void *)TK1_RAM_BASE, *app_size);
|
||||
blake2err = compute_app_digest(ctx->digest);
|
||||
assert(blake2err == 0);
|
||||
print_digest(ctx->digest);
|
||||
|
||||
|
@ -299,7 +313,7 @@ static enum state loading_commands(const struct frame_header *hdr,
|
|||
memcpy_s(&rsp[1], CMDSIZE - 1, &ctx->digest, 32);
|
||||
fwreply(*hdr, FW_RSP_LOAD_APP_DATA_READY, rsp);
|
||||
|
||||
state = FW_STATE_RUN;
|
||||
state = FW_STATE_START;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -319,13 +333,11 @@ static enum state loading_commands(const struct frame_header *hdr,
|
|||
return state;
|
||||
}
|
||||
|
||||
static void run(const struct context *ctx)
|
||||
static void jump_to_app(void)
|
||||
{
|
||||
/* Start of app is always at the beginning of RAM */
|
||||
*app_addr = TK1_RAM_BASE;
|
||||
|
||||
// CDI = hash(uds, hash(app), uss)
|
||||
compute_cdi(ctx->digest, ctx->use_uss, ctx->uss);
|
||||
|
||||
debug_puts("Flipping to app mode!\n");
|
||||
debug_puts("Jumping to ");
|
||||
debug_putinthex(*app_addr);
|
||||
|
@ -364,6 +376,29 @@ static void run(const struct context *ctx)
|
|||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static int load_flash_app(struct partition_table *part_table,
|
||||
uint8_t digest[32], uint8_t slot)
|
||||
{
|
||||
if (slot >= N_PRELOADED_APP) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (preload_load(part_table, slot) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*app_size = part_table->pre_app_data[slot].size;
|
||||
if (*app_size > TK1_APP_MAX_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int digest_err = compute_app_digest(digest);
|
||||
assert(digest_err == 0);
|
||||
print_digest(digest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(SIMULATION)
|
||||
static uint32_t xorwow(uint32_t state, uint32_t acc)
|
||||
{
|
||||
|
@ -398,6 +433,62 @@ static void scramble_ram(void)
|
|||
*ram_data_rand = rnd_word();
|
||||
}
|
||||
|
||||
/* Computes the blake2s digest of the app loaded into RAM */
|
||||
static int compute_app_digest(uint8_t *digest)
|
||||
{
|
||||
return blake2s(digest, 32, NULL, 0, (const void *)TK1_RAM_BASE,
|
||||
*app_size);
|
||||
}
|
||||
|
||||
static enum state start_where(struct context *ctx)
|
||||
{
|
||||
assert(ctx != NULL);
|
||||
|
||||
// Where do we start? Read resetinfo 'startfrom'
|
||||
switch (resetinfo->type) {
|
||||
case START_DEFAULT:
|
||||
// fallthrough
|
||||
case START_FLASH0:
|
||||
ctx->flash_slot = 0;
|
||||
ctx->ver_digest = mgmt_app_allowed_digest();
|
||||
|
||||
return FW_STATE_LOAD_FLASH_MGMT;
|
||||
|
||||
case START_FLASH1:
|
||||
ctx->flash_slot = 1;
|
||||
ctx->ver_digest = NULL;
|
||||
|
||||
return FW_STATE_LOAD_FLASH;
|
||||
|
||||
case START_FLASH0_VER:
|
||||
ctx->flash_slot = 0;
|
||||
ctx->ver_digest = resetinfo->app_digest;
|
||||
|
||||
return FW_STATE_LOAD_FLASH;
|
||||
|
||||
case START_FLASH1_VER:
|
||||
ctx->flash_slot = 1;
|
||||
ctx->ver_digest = resetinfo->app_digest;
|
||||
|
||||
return FW_STATE_LOAD_FLASH;
|
||||
|
||||
case START_CLIENT:
|
||||
ctx->ver_digest = NULL;
|
||||
|
||||
return FW_STATE_WAITCOMMAND;
|
||||
|
||||
case START_CLIENT_VER:
|
||||
ctx->ver_digest = resetinfo->app_digest;
|
||||
|
||||
return FW_STATE_WAITCOMMAND;
|
||||
|
||||
default:
|
||||
debug_puts("Unknown startfrom\n");
|
||||
|
||||
return FW_STATE_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct context ctx = {0};
|
||||
|
@ -405,6 +496,8 @@ int main(void)
|
|||
uint8_t cmd[CMDSIZE] = {0};
|
||||
enum state state = FW_STATE_INITIAL;
|
||||
|
||||
led_set(LED_BLUE);
|
||||
|
||||
print_hw_version();
|
||||
|
||||
/*@-mustfreeonly@*/
|
||||
|
@ -417,6 +510,11 @@ int main(void)
|
|||
|
||||
scramble_ram();
|
||||
|
||||
if (part_table_read(&part_table_storage) != 0) {
|
||||
// Couldn't read or create partition table
|
||||
assert(1 == 2);
|
||||
}
|
||||
|
||||
#if defined(SIMULATION)
|
||||
run(&ctx);
|
||||
#endif
|
||||
|
@ -424,6 +522,10 @@ int main(void)
|
|||
for (;;) {
|
||||
switch (state) {
|
||||
case FW_STATE_INITIAL:
|
||||
state = start_where(&ctx);
|
||||
break;
|
||||
|
||||
case FW_STATE_WAITCOMMAND:
|
||||
if (readcommand(&hdr, cmd, state) == -1) {
|
||||
state = FW_STATE_FAIL;
|
||||
break;
|
||||
|
@ -444,9 +546,52 @@ int main(void)
|
|||
state = loading_commands(&hdr, cmd, state, &ctx);
|
||||
break;
|
||||
|
||||
case FW_STATE_RUN:
|
||||
run(&ctx);
|
||||
break; // This is never reached!
|
||||
case FW_STATE_LOAD_FLASH:
|
||||
if (load_flash_app(&part_table_storage.table,
|
||||
ctx.digest, ctx.flash_slot) < 0) {
|
||||
debug_puts("Couldn't load app from flash\n");
|
||||
state = FW_STATE_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
state = FW_STATE_START;
|
||||
break;
|
||||
|
||||
case FW_STATE_LOAD_FLASH_MGMT:
|
||||
if (load_flash_app(&part_table_storage.table,
|
||||
ctx.digest, ctx.flash_slot) < 0) {
|
||||
debug_puts("Couldn't load app from flash\n");
|
||||
state = FW_STATE_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mgmt_app_init(ctx.digest) != 0) {
|
||||
state = FW_STATE_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
state = FW_STATE_START;
|
||||
break;
|
||||
|
||||
case FW_STATE_START:
|
||||
// CDI = hash(uds, hash(app), uss)
|
||||
compute_cdi(ctx.digest, ctx.use_uss, ctx.uss);
|
||||
|
||||
if (ctx.ver_digest != NULL) {
|
||||
print_digest(ctx.digest);
|
||||
if (!memeq(ctx.digest, (void *)ctx.ver_digest,
|
||||
sizeof(ctx.digest))) {
|
||||
debug_puts("Digests do not match\n");
|
||||
state = FW_STATE_FAIL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(void)memset((void *)resetinfo->app_digest, 0,
|
||||
sizeof(resetinfo->app_digest));
|
||||
|
||||
jump_to_app();
|
||||
break; // Not reached
|
||||
|
||||
case FW_STATE_FAIL:
|
||||
// fallthrough
|
||||
|
@ -461,5 +606,6 @@ int main(void)
|
|||
|
||||
/*@ -compdestroy @*/
|
||||
/* We don't care about memory leaks here. */
|
||||
|
||||
return (int)0xcafebabe;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue