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.
pull/795/head
Daniele Lacamera 2026-06-11 19:54:52 +02:00
parent 809b98ddd6
commit fe934ff277
7 changed files with 583 additions and 133 deletions

9
.gitignore vendored
View File

@ -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

View File

@ -21,6 +21,7 @@
#include <stdint.h>
#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 */

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,10 @@
#ifndef UNIT_TEST_ARM_CMSE_H
#define UNIT_TEST_ARM_CMSE_H
#include <stdint.h>
#define CMSE_NONSECURE 0
#define cmse_check_address_range(ptr, size, flags) \
((void *)(uintptr_t)(ptr))
#endif

View File

@ -0,0 +1,193 @@
#include <check.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
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;
}

View File

@ -0,0 +1,194 @@
#include <check.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#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;
}