diff --git a/hw/application_fpga/Makefile b/hw/application_fpga/Makefile index 4827aed..7c8ce96 100644 --- a/hw/application_fpga/Makefile +++ b/hw/application_fpga/Makefile @@ -93,7 +93,8 @@ FIRMWARE_DEPS = \ $(P)/fw/tk1/auth_app.h \ $(P)/fw/tk1/htif.h \ $(P)/fw/tk1/rng.h \ - $(P)/fw/tk1/mgmt_app.h + $(P)/fw/tk1/mgmt_app.h \ + $(P)/fw/tk1/storage.h FIRMWARE_OBJS = \ $(P)/fw/tk1/main.o \ @@ -110,7 +111,8 @@ FIRMWARE_OBJS = \ $(P)/fw/tk1/auth_app.o \ $(P)/fw/tk1/htif.o \ $(P)/fw/tk1/rng.o \ - $(P)/fw/tk1/mgmt_app.o + $(P)/fw/tk1/mgmt_app.o \ + $(P)/fw/tk1/storage.o FIRMWARE_SOURCES = \ $(P)/fw/tk1/main.c \ @@ -126,7 +128,8 @@ FIRMWARE_SOURCES = \ $(P)/fw/tk1/auth_app.c \ $(P)/fw/tk1/htif.c \ $(P)/fw/tk1/rng.c \ - $(P)/fw/tk1/mgmt_app.c + $(P)/fw/tk1/mgmt_app.c \ + $(P)/fw/tk1/storage.c TESTFW_OBJS = \ $(P)/fw/testfw/main.o \ diff --git a/hw/application_fpga/fw/tk1/storage.c b/hw/application_fpga/fw/tk1/storage.c new file mode 100644 index 0000000..6c29dcb --- /dev/null +++ b/hw/application_fpga/fw/tk1/storage.c @@ -0,0 +1,151 @@ +// Copyright (C) 2024 - Tillitis AB +// SPDX-License-Identifier: GPL-2.0-only + +#include "storage.h" +#include "auth_app.h" +#include "flash.h" +#include "htif.h" +#include "lib.h" +#include "partition_table.h" + +#include +#include +#include + +/* Returns the index of the first empty area. If there is no empty area -1 is + * returned. */ +static int get_first_empty(partition_table_t *part_table) +{ + + for (uint8_t i = 0; i < N_STORAGE_AREA; i++) { + if (part_table->app_storage[i].status == 0x00) { + return i; + } + } + return -1; +} + +/* Returns the index of the area an app has allocated. If no area is + * authenticated -1 is returned. */ +static int storage_get_area(partition_table_t *part_table) +{ + for (uint8_t i = 0; i < N_STORAGE_AREA; i++) { + if (part_table->app_storage[i].status != 0x00) { + if (auth_app_authenticate( + &part_table->app_storage[i].auth)) { + return i; + } + } + } + return -1; +} + +/* Allocate a new area for an app. Returns true if an area is allocated (or + * already was allocated), otherwise false. */ +bool storage_allocate_area(partition_table_t *part_table) +{ + if (storage_get_area(part_table) != -1) { + /* Already has an area */ + return true; + } + int index = get_first_empty(part_table); + + if (index == -1) { + /* No empty slot left */ + return false; + } + + /* Allocate the empty index found */ + part_table->app_storage[index].status = 0x01; + auth_app_create(&part_table->app_storage[index].auth); + + part_table_write(part_table); + + return true; +} + +/* Dealloacate a previously allocated storage area. Returns true on success. */ +bool storage_deallocate_area(partition_table_t *part_table) +{ + int index = storage_get_area(part_table); + if (index == -1) { + /* No area to deallocate */ + return false; + } + + part_table->app_storage[index].status = 0; + + memset(part_table->app_storage[index].auth.nonce, 0x00, + sizeof(part_table->app_storage[index].auth.nonce)); + + memset( + part_table->app_storage[index].auth.authentication_digest, 0x00, + sizeof(part_table->app_storage[index].auth.authentication_digest)); + + part_table_write(part_table); + + flash_block_64_erase(part_table->app_storage[index] + .addr_start); // Erase first 64 KB block + flash_block_64_erase(part_table->app_storage[index].addr_start + + 0x10000); // Erase second 64 KB block + + return true; +} + +/* Writes the specified data to the offset inside of the allocated area. + * Currently only handles writes to one sector, hence max size of 4096 bytes. + * Returns zero on success. */ +int storage_write_data(partition_table_t *part_table, uint32_t offset, + uint8_t *data, size_t size) +{ + int index = storage_get_area(part_table); + if (index == -1) { + /* No allocated area */ + return -1; + } + + if ((offset + size) > part_table->app_storage[index].size || + size > 4096) { + /* Writing outside of area */ + return -2; + } + + uint32_t address = part_table->app_storage[index].addr_start + offset; + + htif_puts("storage: write to addr: "); + htif_putinthex(address); + htif_lf(); + + /* Erase area so we can write */ + /* TODO: Currently only erases one sector, should probably handle sizes + * up to storage size. */ + flash_sector_erase(address); + + return flash_write_data(address, data, size); +} + +/* Reads size bytes of data at the specified offset inside of the allocated + * area. Returns zero on success. Only read limit is the size of the allocated + * area */ +int storage_read_data(partition_table_t *part_table, uint32_t offset, + uint8_t *data, size_t size) +{ + int index = storage_get_area(part_table); + if (index == -1) { + /* No allocated area */ + return -1; + } + + if ((offset + size) > part_table->app_storage[index].size) { + /* Reading outside of area */ + return -2; + } + + uint32_t address = part_table->app_storage[index].addr_start + offset; + + htif_puts("storage: read from addr: "); + htif_putinthex(address); + htif_lf(); + + return flash_read_data(address, data, size); +} diff --git a/hw/application_fpga/fw/tk1/storage.h b/hw/application_fpga/fw/tk1/storage.h new file mode 100644 index 0000000..8a17027 --- /dev/null +++ b/hw/application_fpga/fw/tk1/storage.h @@ -0,0 +1,20 @@ +// Copyright (C) 2024 - Tillitis AB +// SPDX-License-Identifier: GPL-2.0-only + +#ifndef STORAGE_H +#define STORAGE_H + +#include "partition_table.h" + +#include +#include +#include + +bool storage_allocate_area(partition_table_t *part_table); +bool storage_deallocate_area(partition_table_t *part_table); +int storage_write_data(partition_table_t *part_table, uint32_t offset, + uint8_t *data, size_t size); +int storage_read_data(partition_table_t *part_table, uint32_t offset, + uint8_t *data, size_t size); + +#endif