From fe934ff277f31ca1852597f37e7f9e57a69e03d5 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Thu, 11 Jun 2026 19:54:52 +0200 Subject: [PATCH] Fix two regressions after the fenrir changes In hal/va416x0.c, FRAM_Write now explicitly aborts the split SPI write transaction on command-phase failure before returning, instead of leaving the bus in the half-open state introduced by the early return. I also added a host-side regression test in tools/unit-tests/unit-va416x0-fram.c that injects a command-phase HAL_Spi_Transmit(..., false) failure and verifies a later write still reaches the closing ...true phase. In src/arm_tee_psa_ipc.c, I extracted the protected-storage dispatch path into a small helper so it can be tested directly without changing runtime behavior. The new test in tools/unit- tests/unit-arm-tee-psa-ipc.c covers the short-vector invalid-argument branches for SET, GET, GET_INFO, and REMOVE, plus a full success path across those operations. The unit harness additions are wired up in tools/unit-tests/Makefile and use a tiny local CMSE stub in tools/unit-tests/arm_cmse.h. --- .gitignore | 9 + hal/va416x0.c | 19 +- src/arm_tee_psa_ipc.c | 281 +++++++++++++----------- tools/unit-tests/Makefile | 10 + tools/unit-tests/arm_cmse.h | 10 + tools/unit-tests/unit-arm-tee-psa-ipc.c | 193 ++++++++++++++++ tools/unit-tests/unit-va416x0-fram.c | 194 ++++++++++++++++ 7 files changed, 583 insertions(+), 133 deletions(-) create mode 100644 tools/unit-tests/arm_cmse.h create mode 100644 tools/unit-tests/unit-arm-tee-psa-ipc.c create mode 100644 tools/unit-tests/unit-va416x0-fram.c diff --git a/.gitignore b/.gitignore index 03128e24..dad06b30 100644 --- a/.gitignore +++ b/.gitignore @@ -202,6 +202,15 @@ tools/unit-tests/unit-mpusize tools/unit-tests/unit-otp-keystore tools/unit-tests/unit-tpm-api-names tools/unit-tests/unit-elf-bss-guard +tools/unit-tests/unit-fit-fpga +tools/unit-tests/unit-flash-erase-c0 +tools/unit-tests/unit-flash-erase-g0 +tools/unit-tests/unit-flash-erase-l0 +tools/unit-tests/unit-flash-erase-u3 +tools/unit-tests/unit-flash-erase-wb +tools/unit-tests/unit-fwtpm-nv-oob +tools/unit-tests/unit-x86-paging-oob + # Elf preprocessing tools diff --git a/hal/va416x0.c b/hal/va416x0.c index 413c2a28..446e3cd1 100644 --- a/hal/va416x0.c +++ b/hal/va416x0.c @@ -21,6 +21,7 @@ #include +#ifndef WOLFBOOT_UNIT_TEST_VA416X0_FRAM #include "image.h" #include "string.h" @@ -40,7 +41,9 @@ #include "printf.h" #include "loader.h" +#endif +#ifndef WOLFBOOT_UNIT_TEST_VA416X0_FRAM const stc_iocfg_pin_cfg_t bootDefaultConfig[] = { {VOR_PORTB,14,en_iocfg_dir_dncare, {{.fltclk=0,.invinp=0,.iewo=0,.opendrn=0,.invout=0,.plevel=0,.pen=0,.pwoa=0,.funsel=3,.iodis=0}}}, /* UART1 TX */ @@ -163,6 +166,7 @@ void uart_flush(void) while (DEBUG_UART_BASE->TXSTATUS & UART_TXSTATUS_WRBUSY_Msk); } #endif /* DEBUG_UART */ +#endif /* !WOLFBOOT_UNIT_TEST_VA416X0_FRAM */ /* FRAM Driver */ @@ -194,6 +198,15 @@ static void FRAM_WaitIdle(uint8_t spiBank) (SPI_FIFO_CLR_RXFIFO_Msk | SPI_FIFO_CLR_TXFIFO_Msk); } +static void FRAM_AbortWriteTransaction(uint8_t spiBank) +{ + /* Terminate a split write transaction after a command-phase failure so + * the next FRAM operation does not inherit the previous chip-select state. + */ + FRAM_WaitIdle(spiBank); + spiHandle.state = hal_spi_state_ready; +} + /* Init SPI FRAM access */ hal_status_t FRAM_Init(uint8_t spiBank, uint8_t csNum) { @@ -265,8 +278,10 @@ hal_status_t FRAM_Write(uint8_t spiBank, uint32_t addr, uint8_t *buf, spiData[2] = (uint8_t)((addr>>8) & 0xFF); /* Address mid byte */ spiData[3] = (uint8_t)( addr & 0xFF); /* Address low byte */ status = HAL_Spi_Transmit(&spiHandle, spiData, 4, 0, false); - if (status != hal_status_ok) + if (status != hal_status_ok) { + FRAM_AbortWriteTransaction(spiBank); return status; + } return HAL_Spi_Transmit(&spiHandle, buf, len, 0, true); } @@ -326,6 +341,7 @@ hal_status_t FRAM_Erase(uint8_t spiBank, uint32_t addr, uint32_t len) return 0; } +#ifndef WOLFBOOT_UNIT_TEST_VA416X0_FRAM void RAMFUNCTION hal_flash_unlock(void) { @@ -661,3 +677,4 @@ uint64_t hal_get_timer_us(void) ((uint64_t)elapsed_ticks * 1000000ULL / SystemCoreClock); } #endif +#endif /* !WOLFBOOT_UNIT_TEST_VA416X0_FRAM */ diff --git a/src/arm_tee_psa_ipc.c b/src/arm_tee_psa_ipc.c index 5e027fba..aaf75267 100644 --- a/src/arm_tee_psa_ipc.c +++ b/src/arm_tee_psa_ipc.c @@ -262,6 +262,9 @@ static struct wolfboot_ps_entry *wolfboot_ps_alloc(psa_storage_uid_t uid) return NULL; } +static int32_t arm_tee_psa_ps_dispatch(int32_t type, const psa_invec *in_vec, + size_t in_len, psa_outvec *out_vec, size_t out_len); + static psa_status_t wolfboot_psa_open_key(psa_key_id_t id, psa_key_id_t *key) { psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; @@ -774,138 +777,7 @@ static int32_t arm_tee_psa_dispatch(psa_handle_t handle, int32_t type, } if (handle == (psa_handle_t)ARM_TEE_PROTECTED_STORAGE_HANDLE) { - if (type == ARM_TEE_PS_SET) { - const psa_storage_uid_t *uid; - const void *data; - const psa_storage_create_flags_t *flags; - struct wolfboot_ps_entry *entry; - size_t data_len; - if (in_vec == NULL || in_len < 3) { - return PSA_ERROR_INVALID_ARGUMENT; - } - uid = (const psa_storage_uid_t *)in_vec[0].base; - data = in_vec[1].base; - flags = (const psa_storage_create_flags_t *)in_vec[2].base; - /* Snapshot the NS-supplied length once into a Secure-stack local. - * in_vec lives in NS memory and may be mutated concurrently (a - * preempting NS interrupt or NS-accessible DMA), so re-reading - * in_vec[1].len after the bounds check would allow a TOCTOU - * double-fetch to grow the copy past WOLFBOOT_PS_MAX_DATA. */ - data_len = in_vec[1].len; - if (uid == NULL || in_vec[0].len < sizeof(*uid) || - flags == NULL || in_vec[2].len < sizeof(*flags)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - if (data_len > WOLFBOOT_PS_MAX_DATA) { - return PSA_ERROR_INSUFFICIENT_STORAGE; - } - entry = wolfboot_ps_find(*uid); - if (entry == NULL) { - entry = wolfboot_ps_alloc(*uid); - if (entry == NULL) { - return PSA_ERROR_INSUFFICIENT_STORAGE; - } - } else if ((entry->flags & PSA_STORAGE_FLAG_WRITE_ONCE) != 0U) { - return PSA_ERROR_NOT_PERMITTED; - } - if (data_len > 0 && data == NULL) { - return PSA_ERROR_INVALID_ARGUMENT; - } - if (data_len > 0) { - XMEMCPY(entry->data, data, data_len); - } - entry->size = data_len; - entry->flags = *flags; - return PSA_SUCCESS; - } - if (type == ARM_TEE_PS_GET) { - const psa_storage_uid_t *uid; - const rot_size_t *offset; - struct wolfboot_ps_entry *entry; - size_t read_len; - if (in_vec == NULL || in_len < 2 || out_vec == NULL || out_len < 1) { - return PSA_ERROR_INVALID_ARGUMENT; - } - uid = (const psa_storage_uid_t *)in_vec[0].base; - offset = (const rot_size_t *)in_vec[1].base; - if (uid == NULL || in_vec[0].len < sizeof(*uid) || - offset == NULL || in_vec[1].len < sizeof(*offset)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - entry = wolfboot_ps_find(*uid); - if (entry == NULL) { - return PSA_ERROR_DOES_NOT_EXIST; - } - if (*offset > entry->size) { - return PSA_ERROR_INVALID_ARGUMENT; - } - read_len = entry->size - *offset; - if (read_len > out_vec[0].len) { - read_len = out_vec[0].len; - } - if (read_len > 0 && out_vec[0].base != NULL) { - XMEMCPY(out_vec[0].base, entry->data + *offset, read_len); - } - out_vec[0].len = read_len; - return PSA_SUCCESS; - } - if (type == ARM_TEE_PS_GET_INFO) { - const psa_storage_uid_t *uid; - struct wolfboot_ps_entry *entry; - if (in_vec == NULL || in_len < 1 || out_vec == NULL || out_len < 1) { - return PSA_ERROR_INVALID_ARGUMENT; - } - uid = (const psa_storage_uid_t *)in_vec[0].base; - if (uid == NULL || in_vec[0].len < sizeof(*uid)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - entry = wolfboot_ps_find(*uid); - if (entry == NULL) { - return PSA_ERROR_DOES_NOT_EXIST; - } - { - struct psa_storage_info_t info; - info.capacity = WOLFBOOT_PS_MAX_DATA; - info.size = entry->size; - info.flags = entry->flags; - if (out_vec[0].len < sizeof(info)) { - return PSA_ERROR_BUFFER_TOO_SMALL; - } - XMEMCPY(out_vec[0].base, &info, sizeof(info)); - out_vec[0].len = sizeof(info); - } - return PSA_SUCCESS; - } - if (type == ARM_TEE_PS_REMOVE) { - const psa_storage_uid_t *uid; - struct wolfboot_ps_entry *entry; - if (in_vec == NULL || in_len < 1) { - return PSA_ERROR_INVALID_ARGUMENT; - } - uid = (const psa_storage_uid_t *)in_vec[0].base; - if (uid == NULL || in_vec[0].len < sizeof(*uid)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - entry = wolfboot_ps_find(*uid); - if (entry == NULL) { - return PSA_ERROR_DOES_NOT_EXIST; - } - wc_ForceZero(entry->data, sizeof(entry->data)); - entry->in_use = 0; - entry->uid = 0; - entry->size = 0; - entry->flags = 0; - return PSA_SUCCESS; - } - if (type == ARM_TEE_PS_GET_SUPPORT) { - if (out_vec != NULL && out_len >= 1 && out_vec[0].base != NULL) { - uint32_t support = 0; - XMEMCPY(out_vec[0].base, &support, sizeof(support)); - out_vec[0].len = sizeof(support); - } - return PSA_SUCCESS; - } - return PSA_ERROR_NOT_SUPPORTED; + return arm_tee_psa_ps_dispatch(type, in_vec, in_len, out_vec, out_len); } if (handle == (psa_handle_t)ARM_TEE_ATTESTATION_HANDLE) { @@ -1007,6 +879,151 @@ static int32_t arm_tee_psa_dispatch(psa_handle_t handle, int32_t type, return PSA_ERROR_NOT_SUPPORTED; } +static int32_t arm_tee_psa_ps_dispatch(int32_t type, const psa_invec *in_vec, + size_t in_len, psa_outvec *out_vec, size_t out_len) +{ + if (type == ARM_TEE_PS_SET) { + const psa_storage_uid_t *uid; + const void *data; + const psa_storage_create_flags_t *flags; + struct wolfboot_ps_entry *entry; + size_t data_len; + if (in_vec == NULL || in_len < 3) { + return PSA_ERROR_INVALID_ARGUMENT; + } + uid = (const psa_storage_uid_t *)in_vec[0].base; + data = in_vec[1].base; + flags = (const psa_storage_create_flags_t *)in_vec[2].base; + /* Snapshot the NS-supplied length once into a Secure-stack local. + * in_vec lives in NS memory and may be mutated concurrently (a + * preempting NS interrupt or NS-accessible DMA), so re-reading + * in_vec[1].len after the bounds check would allow a TOCTOU + * double-fetch to grow the copy past WOLFBOOT_PS_MAX_DATA. */ + data_len = in_vec[1].len; + if (uid == NULL || in_vec[0].len < sizeof(*uid) || + flags == NULL || in_vec[2].len < sizeof(*flags)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (data_len > WOLFBOOT_PS_MAX_DATA) { + return PSA_ERROR_INSUFFICIENT_STORAGE; + } + entry = wolfboot_ps_find(*uid); + if (entry == NULL) { + entry = wolfboot_ps_alloc(*uid); + if (entry == NULL) { + return PSA_ERROR_INSUFFICIENT_STORAGE; + } + } else if ((entry->flags & PSA_STORAGE_FLAG_WRITE_ONCE) != 0U) { + return PSA_ERROR_NOT_PERMITTED; + } + if (data_len > 0 && data == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (data_len > 0) { + XMEMCPY(entry->data, data, data_len); + } + entry->size = data_len; + entry->flags = *flags; + return PSA_SUCCESS; + } + if (type == ARM_TEE_PS_GET) { + const psa_storage_uid_t *uid; + const rot_size_t *offset; + struct wolfboot_ps_entry *entry; + size_t read_len; + if (in_vec == NULL || in_len < 2 || out_vec == NULL || out_len < 1) { + return PSA_ERROR_INVALID_ARGUMENT; + } + uid = (const psa_storage_uid_t *)in_vec[0].base; + offset = (const rot_size_t *)in_vec[1].base; + if (uid == NULL || in_vec[0].len < sizeof(*uid) || + offset == NULL || in_vec[1].len < sizeof(*offset)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + entry = wolfboot_ps_find(*uid); + if (entry == NULL) { + return PSA_ERROR_DOES_NOT_EXIST; + } + if (*offset > entry->size) { + return PSA_ERROR_INVALID_ARGUMENT; + } + read_len = entry->size - *offset; + if (read_len > out_vec[0].len) { + read_len = out_vec[0].len; + } + if (read_len > 0 && out_vec[0].base != NULL) { + XMEMCPY(out_vec[0].base, entry->data + *offset, read_len); + } + out_vec[0].len = read_len; + return PSA_SUCCESS; + } + if (type == ARM_TEE_PS_GET_INFO) { + const psa_storage_uid_t *uid; + struct wolfboot_ps_entry *entry; + if (in_vec == NULL || in_len < 1 || out_vec == NULL || out_len < 1) { + return PSA_ERROR_INVALID_ARGUMENT; + } + uid = (const psa_storage_uid_t *)in_vec[0].base; + if (uid == NULL || in_vec[0].len < sizeof(*uid)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + entry = wolfboot_ps_find(*uid); + if (entry == NULL) { + return PSA_ERROR_DOES_NOT_EXIST; + } + { + struct psa_storage_info_t info; + info.capacity = WOLFBOOT_PS_MAX_DATA; + info.size = entry->size; + info.flags = entry->flags; + if (out_vec[0].len < sizeof(info)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + XMEMCPY(out_vec[0].base, &info, sizeof(info)); + out_vec[0].len = sizeof(info); + } + return PSA_SUCCESS; + } + if (type == ARM_TEE_PS_REMOVE) { + const psa_storage_uid_t *uid; + struct wolfboot_ps_entry *entry; + if (in_vec == NULL || in_len < 1) { + return PSA_ERROR_INVALID_ARGUMENT; + } + uid = (const psa_storage_uid_t *)in_vec[0].base; + if (uid == NULL || in_vec[0].len < sizeof(*uid)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + entry = wolfboot_ps_find(*uid); + if (entry == NULL) { + return PSA_ERROR_DOES_NOT_EXIST; + } + wc_ForceZero(entry->data, sizeof(entry->data)); + entry->in_use = 0; + entry->uid = 0; + entry->size = 0; + entry->flags = 0; + return PSA_SUCCESS; + } + if (type == ARM_TEE_PS_GET_SUPPORT) { + if (out_vec != NULL && out_len >= 1 && out_vec[0].base != NULL) { + uint32_t support = 0; + XMEMCPY(out_vec[0].base, &support, sizeof(support)); + out_vec[0].len = sizeof(support); + } + return PSA_SUCCESS; + } + return PSA_ERROR_NOT_SUPPORTED; +} + +#ifdef UNIT_TEST +int32_t arm_tee_psa_test_ps_dispatch(int32_t type, const psa_invec *in_vec, + size_t in_len, psa_outvec *out_vec, size_t out_len) +{ + return arm_tee_psa_ps_dispatch(type, in_vec, in_len, out_vec, out_len); +} +#endif + int32_t arm_tee_psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len, psa_outvec *out_vec, size_t out_len) diff --git a/tools/unit-tests/Makefile b/tools/unit-tests/Makefile index 9ebc19be..a40c5230 100644 --- a/tools/unit-tests/Makefile +++ b/tools/unit-tests/Makefile @@ -72,6 +72,8 @@ TESTS+=unit-otp-keystore TESTS+=unit-x86-paging-oob TESTS+=unit-fwtpm-nv-oob TESTS+=unit-elf-bss-guard +TESTS+=unit-arm-tee-psa-ipc +TESTS+=unit-va416x0-fram # linux_loader.c is x86 32-bit only, so its unit tests need a working 32-bit # (multilib) toolchain. Probe whether "gcc -m32" can link, and only add the @@ -277,6 +279,14 @@ unit-store-sbrk: unit-store-sbrk.c ../../src/store_sbrk.c unit-string: ../../include/target.h unit-string.c gcc -o $@ $^ $(CFLAGS) -DDEBUG_UART -DPRINTF_ENABLED $(LDFLAGS) +unit-arm-tee-psa-ipc: ../../include/target.h unit-arm-tee-psa-ipc.c ../../src/arm_tee_psa_ipc.c + gcc -o $@ unit-arm-tee-psa-ipc.c $(CFLAGS) -I$(WOLFBOOT_LIB_WOLFPSA)/wolfpsa \ + -ffunction-sections -fdata-sections \ + $(LDFLAGS) -Wl,--gc-sections + +unit-va416x0-fram: unit-va416x0-fram.c ../../hal/va416x0.c + gcc -o $@ unit-va416x0-fram.c $(CFLAGS) $(LDFLAGS) + unit-max-space: ../../include/target.h unit-max-space.c gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) diff --git a/tools/unit-tests/arm_cmse.h b/tools/unit-tests/arm_cmse.h new file mode 100644 index 00000000..7423acb4 --- /dev/null +++ b/tools/unit-tests/arm_cmse.h @@ -0,0 +1,10 @@ +#ifndef UNIT_TEST_ARM_CMSE_H +#define UNIT_TEST_ARM_CMSE_H + +#include + +#define CMSE_NONSECURE 0 +#define cmse_check_address_range(ptr, size, flags) \ + ((void *)(uintptr_t)(ptr)) + +#endif diff --git a/tools/unit-tests/unit-arm-tee-psa-ipc.c b/tools/unit-tests/unit-arm-tee-psa-ipc.c new file mode 100644 index 00000000..d0e560a1 --- /dev/null +++ b/tools/unit-tests/unit-arm-tee-psa-ipc.c @@ -0,0 +1,193 @@ +#include +#include +#include +#include + +void ForceZero(void *mem, size_t len) +{ + volatile uint8_t *p = (volatile uint8_t *)mem; + + while (len-- > 0) { + *p++ = 0; + } +} + +void wc_ForceZero(void *mem, size_t len) +{ + ForceZero(mem, len); +} + +#include "../../src/arm_tee_psa_ipc.c" + +static void reset_ps_state(void) +{ + memset(g_ps_entries, 0, sizeof(g_ps_entries)); +} + +START_TEST(test_ps_set_rejects_short_uid_vector) +{ + psa_storage_uid_t uid = 0x1122334455667788ULL; + psa_storage_create_flags_t flags = 0; + uint8_t data[4] = {1, 2, 3, 4}; + psa_invec in_vec[3]; + + reset_ps_state(); + in_vec[0].base = &uid; + in_vec[0].len = sizeof(uid) - 1; + in_vec[1].base = data; + in_vec[1].len = sizeof(data); + in_vec[2].base = &flags; + in_vec[2].len = sizeof(flags); + + ck_assert_int_eq( + arm_tee_psa_test_ps_dispatch(ARM_TEE_PS_SET, in_vec, 3, NULL, 0), + PSA_ERROR_INVALID_ARGUMENT); +} +END_TEST + +START_TEST(test_ps_get_rejects_short_offset_vector) +{ + psa_storage_uid_t uid = 7; + rot_size_t offset = 0; + uint8_t out[8]; + psa_invec in_vec[2]; + psa_outvec out_vec[1]; + + reset_ps_state(); + g_ps_entries[0].uid = uid; + g_ps_entries[0].size = 4; + g_ps_entries[0].in_use = 1; + + in_vec[0].base = &uid; + in_vec[0].len = sizeof(uid); + in_vec[1].base = &offset; + in_vec[1].len = sizeof(offset) - 1; + out_vec[0].base = out; + out_vec[0].len = sizeof(out); + + ck_assert_int_eq( + arm_tee_psa_test_ps_dispatch(ARM_TEE_PS_GET, in_vec, 2, out_vec, 1), + PSA_ERROR_INVALID_ARGUMENT); +} +END_TEST + +START_TEST(test_ps_get_info_rejects_short_uid_vector) +{ + psa_storage_uid_t uid = 9; + struct psa_storage_info_t info; + psa_invec in_vec[1]; + psa_outvec out_vec[1]; + + reset_ps_state(); + in_vec[0].base = &uid; + in_vec[0].len = sizeof(uid) - 1; + out_vec[0].base = &info; + out_vec[0].len = sizeof(info); + + ck_assert_int_eq( + arm_tee_psa_test_ps_dispatch(ARM_TEE_PS_GET_INFO, in_vec, 1, out_vec, 1), + PSA_ERROR_INVALID_ARGUMENT); +} +END_TEST + +START_TEST(test_ps_remove_rejects_short_uid_vector) +{ + psa_storage_uid_t uid = 11; + psa_invec in_vec[1]; + + reset_ps_state(); + in_vec[0].base = &uid; + in_vec[0].len = sizeof(uid) - 1; + + ck_assert_int_eq( + arm_tee_psa_test_ps_dispatch(ARM_TEE_PS_REMOVE, in_vec, 1, NULL, 0), + PSA_ERROR_INVALID_ARGUMENT); +} +END_TEST + +START_TEST(test_ps_set_get_info_remove_success_path) +{ + psa_storage_uid_t uid = 0xA5A5A5A5U; + psa_storage_create_flags_t flags = 0; + rot_size_t offset = 1; + uint8_t data[] = {0x10, 0x20, 0x30, 0x40}; + uint8_t read_buf[4] = {0}; + struct psa_storage_info_t info; + psa_invec set_in[3]; + psa_invec get_in[2]; + psa_invec info_in[1]; + psa_invec remove_in[1]; + psa_outvec get_out[1]; + psa_outvec info_out[1]; + + reset_ps_state(); + + set_in[0].base = &uid; + set_in[0].len = sizeof(uid); + set_in[1].base = data; + set_in[1].len = sizeof(data); + set_in[2].base = &flags; + set_in[2].len = sizeof(flags); + ck_assert_int_eq( + arm_tee_psa_test_ps_dispatch(ARM_TEE_PS_SET, set_in, 3, NULL, 0), + PSA_SUCCESS); + + get_in[0].base = &uid; + get_in[0].len = sizeof(uid); + get_in[1].base = &offset; + get_in[1].len = sizeof(offset); + get_out[0].base = read_buf; + get_out[0].len = sizeof(read_buf); + ck_assert_int_eq( + arm_tee_psa_test_ps_dispatch(ARM_TEE_PS_GET, get_in, 2, get_out, 1), + PSA_SUCCESS); + ck_assert_uint_eq(get_out[0].len, sizeof(data) - offset); + ck_assert_mem_eq(read_buf, data + offset, sizeof(data) - offset); + + info_in[0].base = &uid; + info_in[0].len = sizeof(uid); + info_out[0].base = &info; + info_out[0].len = sizeof(info); + ck_assert_int_eq( + arm_tee_psa_test_ps_dispatch(ARM_TEE_PS_GET_INFO, info_in, 1, info_out, 1), + PSA_SUCCESS); + ck_assert_uint_eq(info.size, sizeof(data)); + ck_assert_uint_eq(info.flags, flags); + + remove_in[0].base = &uid; + remove_in[0].len = sizeof(uid); + ck_assert_int_eq( + arm_tee_psa_test_ps_dispatch(ARM_TEE_PS_REMOVE, remove_in, 1, NULL, 0), + PSA_SUCCESS); + ck_assert_int_eq(g_ps_entries[0].in_use, 0); + ck_assert_uint_eq(g_ps_entries[0].size, 0); +} +END_TEST + +Suite *arm_tee_psa_ipc_suite(void) +{ + Suite *s = suite_create("arm-tee-psa-ipc"); + TCase *tc = tcase_create("protected-storage"); + + tcase_add_test(tc, test_ps_set_rejects_short_uid_vector); + tcase_add_test(tc, test_ps_get_rejects_short_offset_vector); + tcase_add_test(tc, test_ps_get_info_rejects_short_uid_vector); + tcase_add_test(tc, test_ps_remove_rejects_short_uid_vector); + tcase_add_test(tc, test_ps_set_get_info_remove_success_path); + suite_add_tcase(s, tc); + + return s; +} + +int main(void) +{ + int fails; + Suite *s = arm_tee_psa_ipc_suite(); + SRunner *sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + fails = srunner_ntests_failed(sr); + srunner_free(sr); + + return fails; +} diff --git a/tools/unit-tests/unit-va416x0-fram.c b/tools/unit-tests/unit-va416x0-fram.c new file mode 100644 index 00000000..9383647f --- /dev/null +++ b/tools/unit-tests/unit-va416x0-fram.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include + +#define WOLFBOOT_UNIT_TEST_VA416X0_FRAM + +#define FRAM_SIZE (256U * 1024U) +#define ROM_SPI_BANK 0 +#define SPI_NUM_BANKS 1 +#define SPI_STATUS_TFE_Msk 0x01U +#define SPI_STATUS_BUSY_Msk 0x02U +#define SPI_FIFO_CLR_RXFIFO_Msk 0x01U +#define SPI_FIFO_CLR_TXFIFO_Msk 0x02U +#define RAMFUNCTION + +typedef enum { + hal_status_ok = 0, + hal_status_badParam = 1, + hal_status_err = 2 +} hal_status_t; + +typedef enum { + hal_spi_state_reset = 0, + hal_spi_state_ready = 1 +} hal_spi_state_t; + +typedef struct { + uint32_t STATUS; + uint32_t FIFO_CLR; +} mock_spi_bank_t; + +typedef struct { + mock_spi_bank_t BANK[SPI_NUM_BANKS]; +} mock_spi_regs_t; + +typedef struct { + bool blockmode; + bool bmstall; + int clkDiv; + bool loopback; + bool mdlycap; + int mode; + int ms; + uint8_t chipSelect; + int wordLen; +} hal_spi_init_t; + +typedef struct { + bool locked; + hal_spi_state_t state; + mock_spi_bank_t *spi; + hal_spi_init_t init; +} hal_spi_handle_t; + +enum { + hal_spi_clkmode_0 = 0, + hal_spi_ms_master = 1 +}; + +static mock_spi_regs_t mock_vor_spi; +#define VOR_SPI (&mock_vor_spi) + +static hal_status_t transmit_script[8]; +static bool transmit_close_flags[8]; +static int transmit_script_len; +static int transmit_call_count; + +static void set_transmit_script(const hal_status_t *script, int len) +{ + int i; + + memset(transmit_close_flags, 0, sizeof(transmit_close_flags)); + for (i = 0; i < len; i++) { + transmit_script[i] = script[i]; + } + transmit_script_len = len; + transmit_call_count = 0; +} + +hal_status_t HAL_Spi_Init(hal_spi_handle_t *handle) +{ + (void)handle; + return hal_status_ok; +} + +hal_status_t HAL_Spi_Transmit(hal_spi_handle_t *handle, uint8_t *data, + uint32_t len, uint32_t timeout, bool close) +{ + (void)handle; + (void)data; + (void)len; + (void)timeout; + + ck_assert_int_lt(transmit_call_count, transmit_script_len); + transmit_close_flags[transmit_call_count] = close; + + return transmit_script[transmit_call_count++]; +} + +hal_status_t HAL_Spi_TransmitReceive(hal_spi_handle_t *handle, uint8_t *tx, + uint8_t *rx, uint32_t tx_len, uint32_t rx_skip, uint32_t rx_len, + uint32_t timeout, bool close) +{ + (void)handle; + (void)tx; + (void)rx; + (void)tx_len; + (void)rx_skip; + (void)rx_len; + (void)timeout; + (void)close; + return hal_status_ok; +} + +void HAL_Timer_DelayMs(uint32_t delay) +{ + (void)delay; +} + +int wolfBoot_printf(const char *fmt, ...) +{ + (void)fmt; + return 0; +} + +#include "../../hal/va416x0.c" + +static void reset_spi_mocks(void) +{ + memset(&mock_vor_spi, 0, sizeof(mock_vor_spi)); + mock_vor_spi.BANK[0].STATUS = SPI_STATUS_TFE_Msk; +} + +START_TEST(test_fram_write_command_failure_aborts_split_transaction) +{ + uint8_t buf[4] = {1, 2, 3, 4}; + hal_status_t init_script[] = { + hal_status_ok, hal_status_ok, hal_status_ok + }; + hal_status_t fail_script[] = { + hal_status_ok, hal_status_err + }; + hal_status_t success_script[] = { + hal_status_ok, hal_status_ok, hal_status_ok + }; + + reset_spi_mocks(); + + set_transmit_script(init_script, 3); + ck_assert_int_eq(FRAM_Init(0, 0), hal_status_ok); + ck_assert_int_eq(spiHandle.state, hal_spi_state_ready); + + set_transmit_script(fail_script, 2); + ck_assert_int_eq(FRAM_Write(0, 0x20, buf, sizeof(buf)), hal_status_err); + ck_assert_int_eq(spiHandle.state, hal_spi_state_ready); + ck_assert_uint_eq(mock_vor_spi.BANK[0].FIFO_CLR, + SPI_FIFO_CLR_RXFIFO_Msk | SPI_FIFO_CLR_TXFIFO_Msk); + ck_assert_int_eq(transmit_call_count, 2); + ck_assert_int_eq(transmit_close_flags[0], true); + ck_assert_int_eq(transmit_close_flags[1], false); + + set_transmit_script(success_script, 3); + ck_assert_int_eq(FRAM_Write(0, 0x24, buf, sizeof(buf)), hal_status_ok); + ck_assert_int_eq(transmit_call_count, 3); + ck_assert_int_eq(transmit_close_flags[0], true); + ck_assert_int_eq(transmit_close_flags[1], false); + ck_assert_int_eq(transmit_close_flags[2], true); +} +END_TEST + +Suite *va416x0_fram_suite(void) +{ + Suite *s = suite_create("va416x0-fram"); + TCase *tc = tcase_create("fram"); + + tcase_add_test(tc, test_fram_write_command_failure_aborts_split_transaction); + suite_add_tcase(s, tc); + + return s; +} + +int main(void) +{ + int fails; + Suite *s = va416x0_fram_suite(); + SRunner *sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + fails = srunner_ntests_failed(sr); + srunner_free(sr); + + return fails; +}