mirror of https://github.com/wolfSSL/wolfBoot.git
va416x0: use pointer-width alignment masks in iram_write/iram_fill
iram_write() and iram_fill() compute the enclosing 32-bit word with (uintptr_t)dst & ~3u. ~3u is a 32-bit constant, so on 64-bit platforms the AND zeroes the high word of the destination pointer and the subsequent word read/write faults (verified: both helpers segfault on x86_64 for any 64-bit destination). On the 32-bit va416x0 target the mask happens to cover the whole pointer, so this only bites where the code runs with 64-bit addresses. Use ~(uintptr_t)3 so the mask is always pointer-width. No behavior change on 32-bit targets. Also make the EXT_FLASH section of hal/va416x0.c host-testable (split the WOLFBOOT_UNIT_TEST_VA416X0_FRAM guard around it, mock the SYSCONFIG register block the lock/unlock pair touches) and add unaligned iram_write/iram_fill regression tests that would segfault pre-fix on the host. Verified: unit-va416x0-fram 3/3 green post-fix (both new tests segfault pre-fix), tools/unit-tests suite green (112 binaries).pull/862/head
parent
4608292b8b
commit
cc8564ae75
|
|
@ -369,7 +369,7 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
|
|||
(void)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !WOLFBOOT_UNIT_TEST_VA416X0_FRAM */
|
||||
|
||||
#ifdef EXT_FLASH
|
||||
void ext_flash_lock(void)
|
||||
|
|
@ -395,7 +395,9 @@ void ext_flash_unlock(void)
|
|||
static void iram_write(void *dst, const void *src, int len)
|
||||
{
|
||||
while (len > 0) {
|
||||
uintptr_t addr = (uintptr_t)dst & ~3u;
|
||||
/* Pointer-width mask: ~3u is 32 bits and would zero the high
|
||||
* word of the address on 64-bit platforms. */
|
||||
uintptr_t addr = (uintptr_t)dst & ~(uintptr_t)3;
|
||||
uint32_t off = (uintptr_t)dst & 3u;
|
||||
uint32_t word = *(volatile uint32_t *)addr;
|
||||
uint8_t *wp = (uint8_t *)&word;
|
||||
|
|
@ -412,7 +414,8 @@ static void iram_write(void *dst, const void *src, int len)
|
|||
static void iram_fill(void *dst, uint8_t val, int len)
|
||||
{
|
||||
while (len > 0) {
|
||||
uintptr_t addr = (uintptr_t)dst & ~3u;
|
||||
/* Pointer-width mask (see iram_write). */
|
||||
uintptr_t addr = (uintptr_t)dst & ~(uintptr_t)3;
|
||||
uint32_t off = (uintptr_t)dst & 3u;
|
||||
uint32_t word = *(volatile uint32_t *)addr;
|
||||
uint8_t *wp = (uint8_t *)&word;
|
||||
|
|
@ -527,6 +530,7 @@ static int test_ext_flash(void)
|
|||
#endif /* TEST_EXT_FLASH */
|
||||
#endif /* EXT_FLASH */
|
||||
|
||||
#ifndef WOLFBOOT_UNIT_TEST_VA416X0_FRAM
|
||||
#ifdef __WOLFBOOT /* build for wolfBoot only */
|
||||
/* Configure Error Detection and Correction (EDAC) */
|
||||
static void ConfigEdac(uint32_t ramScrub, uint32_t romScrub)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,12 @@
|
|||
#include <string.h>
|
||||
|
||||
#define WOLFBOOT_UNIT_TEST_VA416X0_FRAM
|
||||
#define EXT_FLASH
|
||||
|
||||
#define FRAM_SIZE (256U * 1024U)
|
||||
/* The host shadow IRAM lives at a 64-bit pointer address, so keep the
|
||||
* FRAM bounds check from rejecting the test buffer (the hardware value
|
||||
* is 256 KiB). */
|
||||
#define FRAM_SIZE (0xFFFFFFFFU)
|
||||
#define ROM_SPI_BANK 0
|
||||
#define SPI_NUM_BANKS 1
|
||||
#define SPI_STATUS_TFE_Msk 0x01U
|
||||
|
|
@ -61,6 +65,16 @@ enum {
|
|||
static mock_spi_regs_t mock_vor_spi;
|
||||
#define VOR_SPI (&mock_vor_spi)
|
||||
|
||||
/* Mock of the Vorago SYSCONFIG register block (vendor headers are not
|
||||
* available on the host). */
|
||||
typedef struct {
|
||||
uint32_t ROM_PROT;
|
||||
} mock_vor_sysconfig_t;
|
||||
|
||||
static mock_vor_sysconfig_t mock_vor_sysconfig;
|
||||
#define VOR_SYSCONFIG (&mock_vor_sysconfig)
|
||||
#define SYSCONFIG_ROM_PROT_WREN_Msk (1U << 0)
|
||||
|
||||
static hal_status_t transmit_script[8];
|
||||
static bool transmit_close_flags[8];
|
||||
static int transmit_script_len;
|
||||
|
|
@ -169,12 +183,58 @@ START_TEST(test_fram_write_command_failure_aborts_split_transaction)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
/* Shadow IRAM buffer for the ext_flash_erase() tests: the HAL writes
|
||||
* the erased bytes through the raw address, so the address must point
|
||||
* at real host memory. */
|
||||
static uint8_t g_iram[64];
|
||||
|
||||
/* iram_write/iram_fill compute the enclosing word with
|
||||
* (uintptr_t)dst & ~3u - a 32-bit mask. That is the whole pointer on
|
||||
* the 32-bit va416x0 target, but on 64-bit platforms it zeroes the
|
||||
* high word of the address. Unaligned start and end so off != 0 and
|
||||
* the word boundary crossing are exercised. */
|
||||
START_TEST(test_iram_write_unaligned_64bit_addr)
|
||||
{
|
||||
uint8_t data[12];
|
||||
int i;
|
||||
|
||||
memset(g_iram, 0x00, sizeof(g_iram));
|
||||
for (i = 0; i < 12; i++)
|
||||
data[i] = (uint8_t)(0x40 + i);
|
||||
|
||||
iram_write((void *)(g_iram + 1), data, 12);
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
ck_assert_uint_eq(g_iram[1 + i], data[i]);
|
||||
/* Neighboring bytes untouched. */
|
||||
ck_assert_uint_eq(g_iram[0], 0x00);
|
||||
ck_assert_uint_eq(g_iram[13], 0x00);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_iram_fill_unaligned_64bit_addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(g_iram, 0x00, sizeof(g_iram));
|
||||
iram_fill((void *)(g_iram + 2), 0xEE, 10);
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
ck_assert_uint_eq(g_iram[2 + i], 0xEE);
|
||||
ck_assert_uint_eq(g_iram[0], 0x00);
|
||||
ck_assert_uint_eq(g_iram[1], 0x00);
|
||||
ck_assert_uint_eq(g_iram[12], 0x00);
|
||||
}
|
||||
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);
|
||||
tcase_add_test(tc, test_iram_write_unaligned_64bit_addr);
|
||||
tcase_add_test(tc, test_iram_fill_unaligned_64bit_addr);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
|
|
|
|||
Loading…
Reference in New Issue