fw: Move all command switches to their own functions

This commit is contained in:
Michael Cardell Widerkrantz 2023-03-09 15:00:16 +01:00 committed by Daniel Lublin
parent 4e3f5469ef
commit 9de7f294df
No known key found for this signature in database
GPG Key ID: 75BD0FEB8D3E7830

View File

@ -33,6 +33,15 @@ static volatile uint32_t *ram_aslr = (volatile uint32_t *)TK1_MMIO_TK1_RA
static volatile uint32_t *ram_scramble = (volatile uint32_t *)TK1_MMIO_TK1_RAM_SCRAMBLE; static volatile uint32_t *ram_scramble = (volatile uint32_t *)TK1_MMIO_TK1_RAM_SCRAMBLE;
// clang-format on // clang-format on
// Context for the loading of a TKey program
struct context {
int left; // Bytes left to receive
uint8_t digest[32]; // Program digest
uint8_t *loadaddr; // Where we are currently loading a TKey program
uint8_t use_uss; // Use USS?
uint8_t uss[32]; // User Supplied Secret, if any
};
struct namever { struct namever {
char name0[4]; char name0[4];
char name1[4]; char name1[4];
@ -101,7 +110,8 @@ uint32_t rnd_word()
} }
// CDI = blake2s(uds, blake2s(app), uss) // CDI = blake2s(uds, blake2s(app), uss)
static void compute_cdi(uint8_t digest[32], uint8_t use_uss, uint8_t uss[32]) static void compute_cdi(const uint8_t digest[32], const uint8_t use_uss,
const uint8_t uss[32])
{ {
uint32_t local_cdi[8]; uint32_t local_cdi[8];
blake2s_ctx secure_ctx; blake2s_ctx secure_ctx;
@ -141,111 +151,71 @@ static void compute_cdi(uint8_t digest[32], uint8_t use_uss, uint8_t uss[32])
wordcpy_s((void *)cdi, 8, local_cdi, 8); wordcpy_s((void *)cdi, 8, local_cdi, 8);
} }
int main() static int initial_commands(const struct frame_header *hdr, const uint8_t *cmd,
enum state state, struct context *ctx)
{ {
// Set RAM address and data scrambling values uint8_t rsp[CMDLEN_MAXBYTES] = {0};
*ram_aslr = rnd_word();
*ram_scramble = rnd_word();
// Fill RAM with random data (FW does not use RAM, has its stack in
// FW_RAM)
uint32_t *loadaddrw = (uint32_t *)(TK1_RAM_BASE);
uint32_t rnd = rnd_word();
uint32_t rnd_incr = rnd_word();
for (uint32_t w = 0; w < TK1_RAM_SIZE / 4; w++) {
loadaddrw[w] = rnd;
rnd += rnd_incr;
}
// Set new scrambling values, for all use of RAM by app
*ram_aslr = rnd_word();
*ram_scramble = rnd_word();
struct namever namever = get_hw_version(*name0, *name1, *ver);
struct frame_header hdr; // Used in both directions
uint8_t cmd[CMDLEN_MAXBYTES];
uint8_t rsp[CMDLEN_MAXBYTES];
uint8_t *loadaddr = (uint8_t *)TK1_RAM_BASE;
int left = 0; // Bytes left to receive
uint8_t use_uss = FALSE;
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);
for (;;) {
switch (state) {
case FW_STATE_INITIAL:
if (readcommand(&hdr, cmd, state) == -1) {
state = FW_STATE_FAIL;
break;
}
// Reset response buffer
memset(rsp, 0, CMDLEN_MAXBYTES);
switch (cmd[0]) { switch (cmd[0]) {
case FW_CMD_NAME_VERSION: case FW_CMD_NAME_VERSION: {
struct namever namever = get_hw_version(*name0, *name1, *ver);
htif_puts("cmd: name-version\n"); htif_puts("cmd: name-version\n");
if (hdr.len != 1) { if (hdr->len != 1) {
// Bad length - give them an empty // Bad length - give them an empty
// response // response
fwreply(hdr, FW_RSP_NAME_VERSION, rsp); fwreply(*hdr, FW_RSP_NAME_VERSION, rsp);
break; return state;
} }
memcpy_s(rsp, CMDLEN_MAXBYTES, &namever.name0, memcpy_s(rsp, CMDLEN_MAXBYTES, &namever.name0, 4);
4); memcpy_s(&rsp[4], CMDLEN_MAXBYTES - 4, &namever.name1, 4);
memcpy_s(&rsp[4], CMDLEN_MAXBYTES - 4, memcpy_s(&rsp[8], CMDLEN_MAXBYTES - 8, &namever.version, 4);
&namever.name1, 4);
memcpy_s(&rsp[8], CMDLEN_MAXBYTES - 8,
&namever.version, 4);
htif_hexdump(rsp, 12); htif_hexdump(rsp, 12);
fwreply(hdr, FW_RSP_NAME_VERSION, rsp); fwreply(*hdr, FW_RSP_NAME_VERSION, rsp);
// state unchanged // state unchanged
break; return state;
} break;
case FW_CMD_GET_UDI: case FW_CMD_GET_UDI:
htif_puts("cmd: get-udi\n"); htif_puts("cmd: get-udi\n");
if (hdr.len != 1) { if (hdr->len != 1) {
// Bad cmd length // Bad cmd length
rsp[0] = STATUS_BAD; rsp[0] = STATUS_BAD;
fwreply(hdr, FW_RSP_GET_UDI, rsp); fwreply(*hdr, FW_RSP_GET_UDI, rsp);
break; return state;
} }
rsp[0] = STATUS_OK; rsp[0] = STATUS_OK;
uint32_t udi_words[2]; uint32_t udi_words[2];
wordcpy_s(udi_words, 2, (void *)udi, 2); wordcpy_s(udi_words, 2, (void *)udi, 2);
memcpy_s(&rsp[1], CMDLEN_MAXBYTES - 1, memcpy_s(&rsp[1], CMDLEN_MAXBYTES - 1, udi_words, 2 * 4);
udi_words, 2 * 4); fwreply(*hdr, FW_RSP_GET_UDI, rsp);
fwreply(hdr, FW_RSP_GET_UDI, rsp);
// state unchanged // state unchanged
return state;
break; break;
case FW_CMD_LOAD_APP: case FW_CMD_LOAD_APP:
htif_puts("cmd: load-app(size, uss)\n"); htif_puts("cmd: load-app(size, uss)\n");
if (hdr.len != 512) { if (hdr->len != 512) {
// Bad length // Bad length
rsp[0] = STATUS_BAD; rsp[0] = STATUS_BAD;
fwreply(hdr, FW_RSP_LOAD_APP, rsp); fwreply(*hdr, FW_RSP_LOAD_APP, rsp);
break; return state;
} }
// cmd[1..4] contains the size. // cmd[1..4] contains the size.
uint32_t local_app_size = uint32_t local_app_size =
cmd[1] + (cmd[2] << 8) + (cmd[3] << 16) + cmd[1] + (cmd[2] << 8) + (cmd[3] << 16) + (cmd[4] << 24);
(cmd[4] << 24);
htif_puts("app size: "); htif_puts("app size: ");
htif_putinthex(local_app_size); htif_putinthex(local_app_size);
htif_lf(); htif_lf();
if (local_app_size == 0 || if (local_app_size == 0 || local_app_size > TK1_APP_MAX_SIZE) {
local_app_size > TK1_APP_MAX_SIZE) {
rsp[0] = STATUS_BAD; rsp[0] = STATUS_BAD;
fwreply(hdr, FW_RSP_LOAD_APP, rsp); fwreply(*hdr, FW_RSP_LOAD_APP, rsp);
break; return state;
} }
*app_size = local_app_size; *app_size = local_app_size;
@ -253,100 +223,101 @@ int main()
// Do we have a USS at all? // Do we have a USS at all?
if (cmd[5] != 0) { if (cmd[5] != 0) {
// Yes // Yes
use_uss = TRUE; ctx->use_uss = TRUE;
memcpy_s(uss, 32, &cmd[6], 32); memcpy_s(ctx->uss, 32, &cmd[6], 32);
} else { } else {
use_uss = FALSE; ctx->use_uss = FALSE;
} }
rsp[0] = STATUS_OK; rsp[0] = STATUS_OK;
fwreply(hdr, FW_RSP_LOAD_APP, rsp); fwreply(*hdr, FW_RSP_LOAD_APP, rsp);
assert(*app_size != 0); assert(*app_size != 0);
assert(*app_size <= TK1_APP_MAX_SIZE); assert(*app_size <= TK1_APP_MAX_SIZE);
left = *app_size; ctx->left = *app_size;
state = FW_STATE_LOADING;
break;
}
break;
case FW_STATE_LOADING:
if (readcommand(&hdr, cmd, state) == -1) {
state = FW_STATE_FAIL;
break;
}
// Reset response buffer
memset(rsp, 0, CMDLEN_MAXBYTES);
switch (cmd[0]) {
case FW_CMD_LOAD_APP_DATA:
htif_puts("cmd: load-app-data\n");
if (hdr.len != 512) {
// Bad cmd length
rsp[0] = STATUS_BAD;
fwreply(hdr, FW_RSP_LOAD_APP_DATA, rsp);
break;
}
int nbytes;
if (left > (512 - 1)) {
nbytes = 512 - 1;
} else {
nbytes = left;
}
memcpy_s(loadaddr, left, cmd + 1, nbytes);
loadaddr += nbytes;
left -= nbytes;
if (left == 0) {
htif_puts("Fully loaded ");
htif_putinthex(*app_size);
htif_lf();
// Compute Blake2S digest of the app,
// storing it for FW_STATE_RUN
blake2s_ctx ctx;
blake2s(digest, 32, NULL, 0,
(const void *)TK1_RAM_BASE,
*app_size, &ctx);
print_digest(digest);
// And return the digest in final
// response
rsp[0] = STATUS_OK;
memcpy_s(&rsp[1], CMDLEN_MAXBYTES - 1,
&digest, 32);
fwreply(hdr, FW_RSP_LOAD_APP_DATA_READY,
rsp);
state = FW_STATE_RUN;
break;
}
rsp[0] = STATUS_OK;
fwreply(hdr, FW_RSP_LOAD_APP_DATA, rsp);
return FW_STATE_LOADING;
break; break;
default: default:
htif_puts("Got unknown firmware cmd: 0x"); htif_puts("Got unknown firmware cmd: 0x");
htif_puthex(cmd[0]); htif_puthex(cmd[0]);
htif_lf(); htif_lf();
state = FW_STATE_FAIL;
} }
return FW_STATE_FAIL;
}
static int loading_commands(const struct frame_header *hdr, const uint8_t *cmd,
enum state state, struct context *ctx)
{
uint8_t rsp[CMDLEN_MAXBYTES] = {0};
switch (cmd[0]) {
case FW_CMD_LOAD_APP_DATA:
htif_puts("cmd: load-app-data\n");
if (hdr->len != 512) {
// Bad cmd length
rsp[0] = STATUS_BAD;
fwreply(*hdr, FW_RSP_LOAD_APP_DATA, rsp);
return state;
}
int nbytes;
if (ctx->left > (512 - 1)) {
nbytes = 512 - 1;
} else {
nbytes = ctx->left;
}
memcpy_s(ctx->loadaddr, ctx->left, cmd + 1, nbytes);
ctx->loadaddr += nbytes;
ctx->left -= nbytes;
if (ctx->left == 0) {
htif_puts("Fully loaded ");
htif_putinthex(*app_size);
htif_lf();
// Compute Blake2S digest of the app,
// storing it for FW_STATE_RUN
blake2s_ctx b2s_ctx;
blake2s(&ctx->digest, 32, NULL, 0,
(const void *)TK1_RAM_BASE, *app_size,
&b2s_ctx);
print_digest(ctx->digest);
// And return the digest in final
// response
rsp[0] = STATUS_OK;
memcpy_s(&rsp[1], CMDLEN_MAXBYTES - 1, &ctx->digest,
32);
fwreply(*hdr, FW_RSP_LOAD_APP_DATA_READY, rsp);
return FW_STATE_RUN;
}
rsp[0] = STATUS_OK;
fwreply(*hdr, FW_RSP_LOAD_APP_DATA, rsp);
break; break;
case FW_STATE_RUN: default:
htif_puts("state_run\n"); htif_puts("Got unknown firmware cmd: 0x");
htif_puthex(cmd[0]);
htif_lf();
return FW_STATE_FAIL;
}
return state;
}
static void run(const struct context *ctx)
{
*app_addr = TK1_RAM_BASE; *app_addr = TK1_RAM_BASE;
// CDI = hash(uds, hash(app), uss) // CDI = hash(uds, hash(app), uss)
compute_cdi(digest, use_uss, uss); compute_cdi(ctx->digest, ctx->use_uss, ctx->uss);
htif_puts("Flipping to app mode!\n"); htif_puts("Flipping to app mode!\n");
htif_puts("Jumping to "); htif_puts("Jumping to ");
@ -381,6 +352,64 @@ int main()
"jalr x0,0(a0);" "jalr x0,0(a0);"
::: "memory"); ::: "memory");
// clang-format on // clang-format on
__builtin_unreachable();
}
int main()
{
// Set RAM address and data scrambling values
*ram_aslr = rnd_word();
*ram_scramble = rnd_word();
// Fill RAM with random data (FW does not use RAM, has its stack in
// FW_RAM)
uint32_t *loadaddrw = (uint32_t *)(TK1_RAM_BASE);
uint32_t rnd = rnd_word();
uint32_t rnd_incr = rnd_word();
for (uint32_t w = 0; w < TK1_RAM_SIZE / 4; w++) {
loadaddrw[w] = rnd;
rnd += rnd_incr;
}
// Set new scrambling values, for all use of RAM by app
*ram_aslr = rnd_word();
*ram_scramble = rnd_word();
struct context ctx = {0};
struct frame_header hdr; // Used in both directions
uint8_t cmd[CMDLEN_MAXBYTES];
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);
ctx.loadaddr = (uint8_t *)TK1_RAM_BASE;
ctx.use_uss = FALSE;
for (;;) {
switch (state) {
case FW_STATE_INITIAL:
if (readcommand(&hdr, cmd, state) == -1) {
state = FW_STATE_FAIL;
break;
}
state = initial_commands(&hdr, cmd, state, &ctx);
break;
case FW_STATE_LOADING:
if (readcommand(&hdr, cmd, state) == -1) {
state = FW_STATE_FAIL;
break;
}
state = loading_commands(&hdr, cmd, state, &ctx);
break;
case FW_STATE_RUN:
htif_puts("state_run\n");
run(&ctx);
break; // This is never reached! break; // This is never reached!
case FW_STATE_FAIL: case FW_STATE_FAIL: