mirror of https://github.com/wolfSSL/wolfBoot.git
va416x0: fix vector table alignment and length, FRAM defects and ML-DSA
parent
b6509b1c59
commit
e353b20504
|
|
@ -5,9 +5,16 @@ TARGET?=va416x0
|
|||
# ECDSA P384 and SHA384
|
||||
SIGN?=ECC384
|
||||
HASH?=SHA384
|
||||
IMAGE_HEADER_SIZE=512
|
||||
|
||||
# ML-DSA Level 5 (87)
|
||||
# The application vector table sits at BOOT_ADDRESS + IMAGE_HEADER_SIZE and
|
||||
# do_boot() writes that into VTOR. The core ORs the vector offset into VTOR
|
||||
# instead of adding it, so with a 212-entry table any IRQ >= 112 (offset
|
||||
# >= 0x200) is misdispatched unless that address is 1024-aligned. Keep
|
||||
# (BOOT_ADDRESS + IMAGE_HEADER_SIZE) % 1024 == 0; hal/va416x0.c checks it.
|
||||
IMAGE_HEADER_SIZE=1024
|
||||
|
||||
# ML-DSA Level 5 (87). Uses ~48KB of the 64KB SRAM and 34KB of the 36KB
|
||||
# bootloader region, so both are close to full.
|
||||
#SIGN=ML_DSA
|
||||
#HASH=SHA256
|
||||
#ML_DSA_LEVEL=5
|
||||
|
|
|
|||
|
|
@ -8860,19 +8860,46 @@ Tested on VA41620 and VA41630 MCU's.
|
|||
MCU: Cortex-M4 with Triple-Mode Redundancy (TMR) RAD hardening at up to 100MHz.
|
||||
FLASH: The VA41630 has 256KB of internal SPI FRAM (for the VA41620 its external). FRAM is Infineon FM25V20A.
|
||||
|
||||
Default flash layout:
|
||||
Default flash layout, which fills the 256KB FRAM exactly:
|
||||
|
||||
| Partition | Size | Address | Description |
|
||||
|-------------|-------|---------|-------------|
|
||||
| Bootloader | 38KB | 0x0 | Bootloader partition |
|
||||
| Application | 108KB | 0x9800 | Boot partition |
|
||||
| Update | 108KB | 0x24800 | Update partition |
|
||||
| Bootloader | 46KB | 0x0 | Bootloader partition |
|
||||
| Application | 104KB | 0xB800 | Boot partition |
|
||||
| Update | 104KB | 0x25800 | Update partition |
|
||||
| Swap | 2KB | 0x3F800 | Swap area |
|
||||
|
||||
The sector size is 2KB (`WOLFBOOT_SECTOR_SIZE=0x800`) and the manifest header is 1KB (`IMAGE_HEADER_SIZE=1024`), so the application image starts at 0xBC00 and has 0x19C00 bytes of usable space.
|
||||
|
||||
SRAM: 64KB on-chip SRAM and 256KB on-chip instruction/program memory
|
||||
|
||||
The 64KB of SRAM is two contiguous 32KB banks, SRAM_0 at 0x1FFF8000 and SRAM_1 at 0x20000000. The linker scripts pool them into a single region so that data and stack can span both; they remain separate EDAC scrub banks (`RAM0_SCRUB` and `RAM1_SCRUB`). The ML-DSA Level 5 configuration needs about 48KB of it and does not fit in one bank alone.
|
||||
|
||||
Boot ROM loads at 20MHz from SPI bus to internal data SRAM.
|
||||
|
||||
#### Interrupt vector tables
|
||||
|
||||
The VA416xx implements 212 exceptions: the 16 Cortex-M4 system exceptions plus 196 external interrupts, IRQ 0 through `TXEV_IRQn`. Both vector tables are sized for all of them, wolfBoot's in `src/boot_arm.c` and the application's in `test-app/startup_arm.c`. wolfBoot enables the EDAC single-bit and multi-bit error interrupts (76 and 77) when it configures scrubbing, and those vector fetches land at offsets 0x170 and 0x174, so a shorter table sends them into `.text`.
|
||||
|
||||
The application's vector table sits at `WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE` and `do_boot()` writes that address into `SCB->VTOR`. ARMv7-M requires a table this size to be aligned to the next power of two at or above (number of exceptions x 4), which is 1024 bytes for 212 entries, and this part enforces it in a way that is easy to miss.
|
||||
|
||||
`VTOR` itself accepts a finer value: writing `0xFFFFFFFF` reads back `0xFFFFFF80`, so the implemented field is `VTOR[31:7]`. The vector *fetch*, however, ORs the vector offset into `VTOR` rather than adding it, so any vector whose byte offset shares a set bit with the low bits of `VTOR` resolves to the wrong entry. Measured on a VA41630 with a relocated 212-entry table at a 512-aligned (not 1024-aligned) address:
|
||||
|
||||
| IRQ | Vector offset | Result |
|
||||
|-----|---------------|--------|
|
||||
| 77 (`EDAC_SBE`) | 0x174 | dispatched |
|
||||
| 111 | 0x1FC | dispatched |
|
||||
| 112 | 0x200 | hard fault (fetches vector 0, the initial MSP) |
|
||||
| 128 (`PORTD2`) | 0x240 | wrong handler |
|
||||
|
||||
The same table at a 1024-aligned address dispatches IRQ 128 correctly. So a 512-aligned table appears to work -- SysTick, the EDAC interrupts and anything below IRQ 112 are fine -- while every IRQ from 112 upward is silently broken. That covers the PORTA through PORTG pin interrupts, the DMA interrupts and the ADC/DAC interrupts.
|
||||
|
||||
The default layout raises `IMAGE_HEADER_SIZE` to 1024 so that `0xB800 + 0x400 = 0xBC00` satisfies this. That costs 512 bytes of each partition. If you need those bytes back, the alternative is to keep a smaller header and move `WOLFBOOT_PARTITION_BOOT_ADDRESS` instead, so long as the sum stays 1024-aligned; `WOLFBOOT_SECTOR_SIZE` can be reduced to give finer placement, subject to `WOLFBOOT_SECTOR_SIZE >= IMAGE_HEADER_SIZE`. Either way keep `(WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE) % 1024 == 0`. `hal/va416x0.c` checks this at build time, so a layout that breaks the rule fails to compile rather than shipping.
|
||||
|
||||
This applies whichever startup file the application uses. Linking against the Vorago SDK's `startup_va416xx.s` rather than `test-app/startup_arm.c` does not change where wolfBoot places the image, and the SDK's `SystemInit()` sets `VTOR` to the same address wolfBoot already wrote.
|
||||
|
||||
The demo application prints `VTOR`, whether it is 1024-aligned, and a SysTick liveness check at startup, so a truncated or misplaced table is visible on the console. Note that SysTick alone does not prove the table is placed correctly: it is exception 15 at offset 0x3C, below the bit that alignment affects. Testing dispatch properly means triggering an IRQ at or above 112, for example with `NVIC_SetPendingIRQ()`.
|
||||
|
||||
By default the bootloader is built showing logs on UART0. To use UART1 set `DEBUG_UART_NUM=1`. To disable the bootloader UART change `DEBUG_UART=0` in the `.config`.
|
||||
|
||||
### Building Vorago VA416x0
|
||||
|
|
@ -8943,6 +8970,10 @@ Example of wolfBoot binary sizes based on algorithms:
|
|||
| RSA4096 | SHA3-384 | 19,216 |
|
||||
| ML-DSA 87 | SHA256 | 25,168 |
|
||||
|
||||
#### Post-quantum (ML-DSA) configuration
|
||||
|
||||
The example config carries a commented-out ML-DSA Level 5 block: uncomment it, comment out the ECC384/SHA384 lines and the default layout, and use the larger sector and partition sizes it lists. The `sign` tool reads `ML_DSA_LEVEL` from the environment and otherwise falls back to level 2, which rejects a level 5 key with `error: unrecognized ml-dsa key size: 7488`. The top-level Makefile and `tools/scripts/va416x0/build_test.sh` both pass it for you; a hand-run `sign` needs it on the command line.
|
||||
|
||||
### Flashing Vorago VA416x0
|
||||
|
||||
Flash using Segger JLink: `JLinkExe -CommanderScript tools/scripts/va416x0/flash_va416xx.jlink`
|
||||
|
|
@ -8967,14 +8998,16 @@ The `loader.elf` programs the external SPI FRAM with the IRAM image. It is creat
|
|||
|
||||
See `tools/scripts/va416x0/build_test.sh clean` for flashing examples.
|
||||
|
||||
Example boot ouput on UART 0 (MCU TX):
|
||||
Example boot output on UART 0 (MCU TX):
|
||||
|
||||
```
|
||||
wolfBoot HAL Init
|
||||
Boot partition: 0x9800 (sz 5060, ver 0x1, type 0x601)
|
||||
Partition 1 header magic 0x00000000 invalid at 0x24800
|
||||
Boot partition: 0x9800 (sz 5060, ver 0x1, type 0x601)
|
||||
Boot partition: 0xB800 (sz 5600, ver 0x1, type 0x601)
|
||||
Partition 1 header magic 0x00000000 invalid at 0x25800
|
||||
Boot partition: 0xB800 (sz 5600, ver 0x1, type 0x601)
|
||||
Booting version: 0x1
|
||||
Checking integrity...done
|
||||
Verifying signature...done
|
||||
========================
|
||||
VA416x0 wolfBoot demo Application
|
||||
Copyright 2025 wolfSSL Inc
|
||||
|
|
@ -9000,8 +9033,19 @@ Number of public keys: 1
|
|||
9B BE B7 BB 11 75 01 81 45 14 19 7E B2 BD C0 A6
|
||||
11 0C FA F6 B5 F9 59 BA B9 A5 8E 34 4A CD C5 83
|
||||
7E 43 EF 61 6E C4 15 88 3C FE D6 76 47 D9 82 A4
|
||||
|
||||
Vector table
|
||||
====================================
|
||||
VTOR : 0x0000BC00 (expected 0x0000BC00) OK
|
||||
SysTick : ticking (113 -> 1738 ms)
|
||||
```
|
||||
|
||||
`VTOR` is the address the core fetches exceptions from, and it must match
|
||||
`WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE`. The SysTick line is a
|
||||
liveness check: `HAL_Init()` starts SysTick and `SysTick_Handler()` advances
|
||||
`HAL_time_ms`, so a counter that never moves means exceptions are not reaching
|
||||
the application's vector table.
|
||||
|
||||
### Debugging Vorago VA416x0
|
||||
|
||||
Start the GDB server: `JLinkGDBServer -device VA416XX -if SWD -speed 2000 -port 3333`
|
||||
|
|
@ -9014,7 +9058,7 @@ See `tools/scripts/va416x0/build_test.sh update`:
|
|||
|
||||
```sh
|
||||
# Sign a new test app with version 2
|
||||
IMAGE_HEADER_SIZE=512 ./tools/keytools/sign --ecc384 --sha384 test-app/image.bin wolfboot_signing_private_key.der 2
|
||||
IMAGE_HEADER_SIZE=1024 ./tools/keytools/sign --ecc384 --sha384 test-app/image.bin wolfboot_signing_private_key.der 2
|
||||
|
||||
# Create a bin footer with wolfBoot trailer "BOOT" and "p" (ASCII for 0x70 == IMG_STATE_UPDATING)
|
||||
echo -n "pBOOT" > trigger_magic.bin
|
||||
|
|
@ -9046,17 +9090,17 @@ Example update output:
|
|||
|
||||
```
|
||||
wolfBoot HAL Init
|
||||
Boot partition: 0x9800 (sz 5060, ver 0x1, type 0x601)
|
||||
Update partition: 0x24800 (sz 5060, ver 0x2, type 0x601)
|
||||
Boot partition: 0xB800 (sz 5600, ver 0x1, type 0x601)
|
||||
Update partition: 0x25800 (sz 5600, ver 0x2, type 0x601)
|
||||
Starting Update (fallback allowed 0)
|
||||
Update partition: 0x24800 (sz 5060, ver 0x2, type 0x601)
|
||||
Boot partition: 0x9800 (sz 5060, ver 0x1, type 0x601)
|
||||
Update partition: 0x25800 (sz 5600, ver 0x2, type 0x601)
|
||||
Boot partition: 0xB800 (sz 5600, ver 0x1, type 0x601)
|
||||
Versions: Current 0x1, Update 0x2
|
||||
Copy sector 0 (part 1->2)
|
||||
Copy sector 0 (part 0->1)
|
||||
Copy sector 0 (part 2->0)
|
||||
Boot partition: 0x9800 (sz 5060, ver 0x2, type 0x601)
|
||||
Update partition: 0x24800 (sz 5060, ver 0x1, type 0x601)
|
||||
Boot partition: 0xB800 (sz 5600, ver 0x2, type 0x601)
|
||||
Update partition: 0x25800 (sz 5600, ver 0x1, type 0x601)
|
||||
Copy sector 1 (part 1->2)
|
||||
Copy sector 1 (part 0->1)
|
||||
Copy sector 1 (part 2->0)
|
||||
|
|
@ -9064,11 +9108,11 @@ Copy sector 2 (part 1->2)
|
|||
Copy sector 2 (part 0->1)
|
||||
Copy sector 2 (part 2->0)
|
||||
Erasing remainder of partition (50 sectors)...
|
||||
Boot partition: 0x9800 (sz 5060, ver 0x2, type 0x601)
|
||||
Update partition: 0x24800 (sz 5060, ver 0x1, type 0x601)
|
||||
Boot partition: 0xB800 (sz 5600, ver 0x2, type 0x601)
|
||||
Update partition: 0x25800 (sz 5600, ver 0x1, type 0x601)
|
||||
Copy sector 52 (part 0->2)
|
||||
Copied boot sector to swap
|
||||
Boot partition: 0x9800 (sz 5060, ver 0x2, type 0x601)
|
||||
Boot partition: 0xB800 (sz 5600, ver 0x2, type 0x601)
|
||||
Booting version: 0x1
|
||||
========================
|
||||
VA416x0 wolfBoot demo Application
|
||||
|
|
@ -9105,9 +9149,9 @@ Boot logs after hard reset:
|
|||
|
||||
```
|
||||
wolfBoot HAL Init
|
||||
Boot partition: 0x9800 (sz 5060, ver 0x2, type 0x601)
|
||||
Update partition: 0x24800 (sz 5060, ver 0x1, type 0x601)
|
||||
Boot partition: 0x9800 (sz 5060, ver 0x2, type 0x601)
|
||||
Boot partition: 0xB800 (sz 5600, ver 0x2, type 0x601)
|
||||
Update partition: 0x25800 (sz 5600, ver 0x1, type 0x601)
|
||||
Boot partition: 0xB800 (sz 5600, ver 0x2, type 0x601)
|
||||
Booting version: 0x2
|
||||
========================
|
||||
VA416x0 wolfBoot demo Application
|
||||
|
|
|
|||
|
|
@ -41,6 +41,15 @@
|
|||
|
||||
#include "printf.h"
|
||||
#include "loader.h"
|
||||
|
||||
/* The application vector table must be 1024-aligned: this core ORs the vector
|
||||
* offset into VTOR rather than adding it, so with 212 entries every IRQ >= 112
|
||||
* misdispatches otherwise. See docs/Targets.md. */
|
||||
#if defined(WOLFBOOT_PARTITION_BOOT_ADDRESS) && defined(IMAGE_HEADER_SIZE)
|
||||
#if (((WOLFBOOT_PARTITION_BOOT_ADDRESS) + (IMAGE_HEADER_SIZE)) & 0x3FF) != 0
|
||||
#error "VA416x0: application vector table must be 1024-aligned. Raise IMAGE_HEADER_SIZE (1024) or move WOLFBOOT_PARTITION_BOOT_ADDRESS."
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef WOLFBOOT_UNIT_TEST_VA416X0_FRAM
|
||||
|
|
@ -117,22 +126,11 @@ static void UartInit(VOR_UART_Type* uart, uint32_t baudrate)
|
|||
uart->CTRL |= UART_CTRL_AUTORTS_Msk;
|
||||
#endif
|
||||
|
||||
/* Enable RX interrupts as soon as a character is received */
|
||||
uart->IRQ_ENB = UART_IRQ_ENB_IRQ_RX_Msk;
|
||||
uart->RXFIFOIRQTRG = 1;
|
||||
/* Transmit-only: nothing reads the UART, and __HAL_DISABLE_UART0/1/2
|
||||
* means the SDK builds no UART IRQ handler to vector to. */
|
||||
uart->IRQ_ENB = 0;
|
||||
uart->TXFIFOIRQTRG = 8;
|
||||
|
||||
if (VOR_UART0 == uart) {
|
||||
NVIC_SetPriority(UART0_RX_IRQn, 1);
|
||||
NVIC_EnableIRQ(UART0_RX_IRQn);
|
||||
} else if (VOR_UART1 == uart) {
|
||||
NVIC_SetPriority(UART1_RX_IRQn, 1);
|
||||
NVIC_EnableIRQ(UART1_RX_IRQn);
|
||||
} else {
|
||||
NVIC_SetPriority(UART2_RX_IRQn, 1);
|
||||
NVIC_EnableIRQ(UART2_RX_IRQn);
|
||||
}
|
||||
|
||||
/* Enable UART */
|
||||
uart->ENABLE = (UART_ENABLE_RXENABLE_Msk |
|
||||
UART_ENABLE_TXENABLE_Msk);
|
||||
|
|
@ -181,7 +179,10 @@ void uart_flush(void)
|
|||
#define FRAM_SLEEP 0xB9
|
||||
|
||||
#ifndef USE_HAL_SPI_FRAM
|
||||
/* One FRAM device at a time: transmits always use spiHandle, so record its
|
||||
* bank and reject any other rather than drain one bank and transmit on it. */
|
||||
static hal_spi_handle_t spiHandle;
|
||||
static uint8_t spiFramBank = SPI_NUM_BANKS; /* invalid until a good init */
|
||||
|
||||
static void FRAM_WaitIdle(uint8_t spiBank)
|
||||
{
|
||||
|
|
@ -213,6 +214,11 @@ hal_status_t FRAM_Init(uint8_t spiBank, uint8_t csNum)
|
|||
hal_status_t status = hal_status_ok;
|
||||
uint8_t spiData[2];
|
||||
|
||||
/* Bounds check before indexing BANK[], as FRAM_WaitIdle() does */
|
||||
if (spiBank >= SPI_NUM_BANKS) {
|
||||
return hal_status_badParam;
|
||||
}
|
||||
|
||||
/* Initialize the SPI handle */
|
||||
memset(&spiHandle, 0, sizeof(spiHandle));
|
||||
spiHandle.locked = false;
|
||||
|
|
@ -243,6 +249,16 @@ hal_status_t FRAM_Init(uint8_t spiBank, uint8_t csNum)
|
|||
FRAM_WaitIdle(spiBank);
|
||||
spiHandle.state = hal_spi_state_ready;
|
||||
}
|
||||
if (status == hal_status_ok) {
|
||||
/* Only bind on success: a failed init must not leave the gate open */
|
||||
spiFramBank = spiBank;
|
||||
}
|
||||
else {
|
||||
/* spiHandle was already repointed at spiBank but never brought up.
|
||||
* Close the gate rather than leave it naming a previously good
|
||||
* bank that the handle no longer refers to. */
|
||||
spiFramBank = SPI_NUM_BANKS;
|
||||
}
|
||||
wolfBoot_printf("FRAM_Init: status %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
|
@ -254,11 +270,11 @@ hal_status_t FRAM_Write(uint8_t spiBank, uint32_t addr, uint8_t *buf,
|
|||
uint8_t spiData[4];
|
||||
|
||||
/* Validate input parameters */
|
||||
if (buf == NULL || len == 0) {
|
||||
if (buf == NULL || len == 0 || spiBank != spiFramBank) {
|
||||
return hal_status_badParam;
|
||||
}
|
||||
/* Bounds check: ensure write doesn't exceed FRAM size */
|
||||
if (addr >= FRAM_SIZE || (addr + len) > FRAM_SIZE) {
|
||||
/* Compare against the space remaining: addr + len could wrap */
|
||||
if (addr >= FRAM_SIZE || len > (uint32_t)FRAM_SIZE - addr) {
|
||||
return hal_status_badParam;
|
||||
}
|
||||
|
||||
|
|
@ -291,11 +307,11 @@ hal_status_t FRAM_Read(uint8_t spiBank, uint32_t addr, uint8_t *buf,
|
|||
uint8_t spiData[4];
|
||||
|
||||
/* Validate input parameters */
|
||||
if (buf == NULL || len == 0) {
|
||||
if (buf == NULL || len == 0 || spiBank != spiFramBank) {
|
||||
return hal_status_badParam;
|
||||
}
|
||||
/* Bounds check: ensure read doesn't exceed FRAM size */
|
||||
if (addr >= FRAM_SIZE || (addr + len) > FRAM_SIZE) {
|
||||
/* Compare against the space remaining: addr + len could wrap */
|
||||
if (addr >= FRAM_SIZE || len > (uint32_t)FRAM_SIZE - addr) {
|
||||
return hal_status_badParam;
|
||||
}
|
||||
|
||||
|
|
@ -331,7 +347,7 @@ hal_status_t FRAM_Erase(uint8_t spiBank, uint32_t addr, uint32_t len)
|
|||
|
||||
while (len > 0) {
|
||||
uint32_t erase_len = (len > sizeof(data)) ? sizeof(data) : len;
|
||||
status = FRAM_Write(ROM_SPI_BANK, addr, data, erase_len);
|
||||
status = FRAM_Write(spiBank, addr, data, erase_len);
|
||||
if (status != hal_status_ok) {
|
||||
/* Return the hal_status_t unmodified; ext_flash_erase() is
|
||||
* the single negation point to a negative error code. */
|
||||
|
|
@ -355,21 +371,21 @@ void RAMFUNCTION hal_flash_lock(void)
|
|||
|
||||
}
|
||||
|
||||
/* No internal flash. All partitions are external (PART_*_EXT), so these are
|
||||
* unreachable; return an error so a config that reaches them fails loudly. */
|
||||
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
|
||||
{
|
||||
/* not supported - no internal flash */
|
||||
(void)address;
|
||||
(void)data;
|
||||
(void)len;
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
|
||||
{
|
||||
/* not supported - no internal flash */
|
||||
(void)address;
|
||||
(void)len;
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
#endif /* !WOLFBOOT_UNIT_TEST_VA416X0_FRAM */
|
||||
|
||||
|
|
@ -448,6 +464,8 @@ int ext_flash_write(uintptr_t address, const uint8_t *data, int len)
|
|||
return len;
|
||||
}
|
||||
|
||||
/* The shadow update below re-syncs IRAM from FRAM, so it is a repair rather
|
||||
* than a cache fill, and is a no-op unless the caller holds ROM_PROT.WREN. */
|
||||
int ext_flash_read(uintptr_t address, uint8_t *data, int len)
|
||||
{
|
||||
hal_status_t status;
|
||||
|
|
@ -494,7 +512,8 @@ static int test_ext_flash(void)
|
|||
{
|
||||
int ret;
|
||||
uint32_t i;
|
||||
uint8_t pageData[WOLFBOOT_SECTOR_SIZE] = { 0 };
|
||||
/* static: WOLFBOOT_SECTOR_SIZE is far too large for the stack */
|
||||
static uint8_t pageData[WOLFBOOT_SECTOR_SIZE];
|
||||
|
||||
#ifndef READONLY
|
||||
/* Erase sector */
|
||||
|
|
@ -563,7 +582,7 @@ void hal_init(void)
|
|||
/* Configure PLL to set CPU clock to 100MHz - 40MHz crystal * 2.5 */
|
||||
status = HAL_Clkgen_PLL(CLK_CTRL0_XTAL_N_PLL2P5X);
|
||||
if (status != hal_status_ok) {
|
||||
/* continue anyways */
|
||||
/* continue anyways: no UART yet, so this cannot be reported */
|
||||
}
|
||||
|
||||
/* Disable Watchdog - should be already disabled out of reset */
|
||||
|
|
@ -581,13 +600,13 @@ void hal_init(void)
|
|||
/* Call SDK HAL initialization function */
|
||||
status = HAL_Init();
|
||||
if (status != hal_status_ok) {
|
||||
/* continue anyways */
|
||||
/* continue anyways: no UART yet, so this cannot be reported */
|
||||
}
|
||||
|
||||
/* Configure the pins */
|
||||
status = HAL_Iocfg_SetupPins(bootDefaultConfig);
|
||||
if (status != hal_status_ok) {
|
||||
/* continue anyways */
|
||||
/* continue anyways: no UART yet, so this cannot be reported */
|
||||
}
|
||||
|
||||
#ifdef DEBUG_UART
|
||||
|
|
@ -600,10 +619,8 @@ void hal_init(void)
|
|||
/* Init the FRAM SPI device */
|
||||
status = FRAM_Init(ROM_SPI_BANK, ROM_SPI_CSN);
|
||||
if (status != hal_status_ok) {
|
||||
#ifdef DEBUG
|
||||
wolfBoot_printf("FRAM_Init failed\n");
|
||||
#endif
|
||||
/* continue anyways */
|
||||
wolfBoot_printf("FRAM_Init failed: status %d\n", status);
|
||||
/* Continue: the image checks fail closed if FRAM is unreadable */
|
||||
}
|
||||
|
||||
#ifdef TEST_EXT_FLASH
|
||||
|
|
@ -616,19 +633,10 @@ void hal_prepare_boot(void)
|
|||
#ifdef DEBUG_UART
|
||||
uart_flush();
|
||||
|
||||
/* Disable UART to give app a clean state */
|
||||
/* Disable UART to give app a clean state. UartInit() enables no UART
|
||||
* interrupt, so there is no NVIC state to unwind here. */
|
||||
DEBUG_UART_BASE->IRQ_ENB = 0;
|
||||
DEBUG_UART_BASE->ENABLE = 0;
|
||||
#if defined(DEBUG_UART_NUM) && DEBUG_UART_NUM == 1
|
||||
NVIC_DisableIRQ(UART1_RX_IRQn);
|
||||
NVIC_ClearPendingIRQ(UART1_RX_IRQn);
|
||||
#elif defined(DEBUG_UART_NUM) && DEBUG_UART_NUM == 2
|
||||
NVIC_DisableIRQ(UART2_RX_IRQn);
|
||||
NVIC_ClearPendingIRQ(UART2_RX_IRQn);
|
||||
#else /* default: UART0 */
|
||||
NVIC_DisableIRQ(UART0_RX_IRQn);
|
||||
NVIC_ClearPendingIRQ(UART0_RX_IRQn);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WOLFBOOT_RESTORE_CLOCK
|
||||
|
|
|
|||
|
|
@ -70,11 +70,13 @@
|
|||
|
||||
/** Default pin IOCONFIG register. type: un_iocfg_reg_t - see va416xx_hal_ioconfig.h */
|
||||
/** A pin's IOCONFIG is set to this by HAL_Iocfg_Init() if that pin is not in the cfg array */
|
||||
#define DEFAULT_PIN_IOCFG (IOCFG_REG_PULLDN) // internal pulldown enabled for input pin
|
||||
/* internal pulldown enabled for input pin */
|
||||
#define DEFAULT_PIN_IOCFG (IOCFG_REG_PULLDN)
|
||||
|
||||
/** Default pin direction (input/output) type: en_iocfg_dir_t - see va416xx_hal_ioconfig.h */
|
||||
/** A pin's DIR is set to this by HAL_Iocfg_Init() if that pin is not in the cfg array */
|
||||
#define DEFAULT_PIN_DIR (en_iocfg_dir__input) // default pin input
|
||||
/* default pin direction is input */
|
||||
#define DEFAULT_PIN_DIR (en_iocfg_dir__input)
|
||||
|
||||
|
||||
/* PEB1-VA416XX-EVK */
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ MEMORY
|
|||
{
|
||||
IRAM (rx) :ORIGIN = 0x00000000, LENGTH = 256K
|
||||
EBI (xrw) :ORIGIN = 0x10000000, LENGTH = 16M
|
||||
RAM0 (xrw) :ORIGIN = 0x1FFF8000, LENGTH = 32K
|
||||
RAM1 (xrw) :ORIGIN = 0x20000000, LENGTH = 32K
|
||||
/* SRAM_0 (0x1FFF8000) and SRAM_1 (0x20000000) are contiguous, so they are
|
||||
pooled as one 64K region. They stay separate EDAC scrub banks. */
|
||||
RAM0 (xrw) :ORIGIN = 0x1FFF8000, LENGTH = 64K
|
||||
}
|
||||
|
||||
/* Define output sections */
|
||||
|
|
@ -132,13 +133,13 @@ SECTIONS
|
|||
__bss_end__ = _end_bss;
|
||||
} >RAM0
|
||||
|
||||
/* DMA control block, goes into fixed location in RAM1 */
|
||||
/* DMA control block. Empty unless the SDK DMA driver is linked in; the
|
||||
engine only requires the 128 byte alignment. */
|
||||
.dma_blk (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(128);
|
||||
/**(.ARM.__at_0x20000000) */
|
||||
*(dma_blk)
|
||||
} >RAM1
|
||||
} >RAM0
|
||||
|
||||
/* User_stack section, used to check that there is enough RAM left */
|
||||
._user_stack :
|
||||
|
|
|
|||
206
src/boot_arm.c
206
src/boot_arm.c
|
|
@ -837,8 +837,214 @@ void (* const IV[])(void) =
|
|||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
#elif defined(TARGET_va416x0)
|
||||
/* IRQ 0 through TXEV_IRQn (195), for 212 entries. wolfBoot enables the
|
||||
* EDAC error IRQs (76, 77), so those slots must exist. */
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef TARGET_va416x0
|
||||
/* 16 system exceptions + 196 external IRQs. A short table sends the EDAC
|
||||
* error IRQs (76, 77) into .text; fail the build instead. */
|
||||
typedef char va416x0_iv_len_check[
|
||||
(sizeof(IV) / sizeof(IV[0]) == 212) ? 1 : -1];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef RAM_CODE
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ MEMORY
|
|||
{
|
||||
IRAM (rx) :ORIGIN = @WOLFBOOT_TEST_APP_ADDRESS@, LENGTH = @WOLFBOOT_TEST_APP_SIZE@
|
||||
EBI (xrw) :ORIGIN = 0x10000000, LENGTH = 16M
|
||||
RAM0 (xrw) :ORIGIN = 0x1FFF8000, LENGTH = 32K
|
||||
RAM1 (xrw) :ORIGIN = 0x20000000, LENGTH = 32K
|
||||
/* SRAM_0 (0x1FFF8000) and SRAM_1 (0x20000000) are contiguous, so they are
|
||||
pooled as one 64K region. They stay separate EDAC scrub banks. */
|
||||
RAM0 (xrw) :ORIGIN = 0x1FFF8000, LENGTH = 64K
|
||||
}
|
||||
|
||||
/* Define output sections */
|
||||
|
|
@ -132,13 +133,13 @@ SECTIONS
|
|||
__bss_end__ = _end_bss;
|
||||
} >RAM0
|
||||
|
||||
/* DMA control block, goes into fixed location in RAM1 */
|
||||
/* DMA control block. Empty unless the SDK DMA driver is linked in; the
|
||||
engine only requires the 128 byte alignment. */
|
||||
.dma_blk (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(128);
|
||||
/**(.ARM.__at_0x20000000) */
|
||||
*(dma_blk)
|
||||
} >RAM1
|
||||
} >RAM0
|
||||
|
||||
/* User_heap_stack section, used to check that there is enough RAM left */
|
||||
._user_heap_stack :
|
||||
|
|
|
|||
|
|
@ -55,6 +55,44 @@ int benchmark_test(void *args);
|
|||
#include "va416xx_hal_timer.h"
|
||||
#include "va416xx_hal_ioconfig.h"
|
||||
|
||||
/* Confirm VTOR points at the application's table and that exceptions reach it.
|
||||
* SysTick advances HAL_time_ms, so a frozen counter means they do not. */
|
||||
static void print_vector_table_info(void)
|
||||
{
|
||||
uint32_t vtor;
|
||||
uint32_t expect;
|
||||
uint32_t t0, t1; /* short delta; keeps the print 32-bit */
|
||||
volatile uint32_t spin;
|
||||
|
||||
vtor = SCB->VTOR;
|
||||
expect = (uint32_t)(WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE);
|
||||
|
||||
wolfBoot_printf("\r\n");
|
||||
wolfBoot_printf("Vector table\r\n");
|
||||
wolfBoot_printf("====================================\r\n");
|
||||
wolfBoot_printf("VTOR : 0x%08lx (expected 0x%08lx) %s\r\n",
|
||||
(unsigned long)vtor, (unsigned long)expect,
|
||||
(vtor == expect) ? "OK" : "MISMATCH");
|
||||
|
||||
/* The core ORs the vector offset into VTOR rather than adding it, so a
|
||||
* 212-entry table that is not 1024-aligned misdispatches every IRQ from
|
||||
* 112 up while SysTick and the EDAC IRQs still look healthy. */
|
||||
wolfBoot_printf("VT alignment : %lu %s\r\n",
|
||||
(unsigned long)(vtor & 0x3FFU),
|
||||
((vtor & 0x3FFU) == 0) ? "(1024-aligned) OK"
|
||||
: "*** NOT 1024-ALIGNED: IRQ >= 112 broken ***");
|
||||
|
||||
t0 = (uint32_t)HAL_time_ms;
|
||||
/* Bounded: HAL_Timer_DelayMs() spins on HAL_time_ms and would hang */
|
||||
for (spin = 0; spin < 2000000UL; spin++) {
|
||||
}
|
||||
t1 = (uint32_t)HAL_time_ms;
|
||||
|
||||
wolfBoot_printf("SysTick : %s (%lu -> %lu ms)\r\n",
|
||||
(t1 != t0) ? "ticking" : "STOPPED",
|
||||
(unsigned long)t0, (unsigned long)t1);
|
||||
}
|
||||
|
||||
static uint8_t boot_part_state = IMG_STATE_NEW;
|
||||
static uint8_t update_part_state = IMG_STATE_NEW;
|
||||
|
||||
|
|
@ -87,10 +125,9 @@ static const char *part_state_name(uint8_t state)
|
|||
|
||||
static int print_info(void)
|
||||
{
|
||||
int i, j;
|
||||
uint32_t i, j;
|
||||
uint32_t cur_fw_version, update_fw_version;
|
||||
uint32_t n_keys;
|
||||
uint16_t hdrSz;
|
||||
|
||||
cur_fw_version = wolfBoot_current_firmware_version();
|
||||
update_fw_version = wolfBoot_update_firmware_version();
|
||||
|
|
@ -130,8 +167,8 @@ static int print_info(void)
|
|||
uint8_t *keybuf = keystore_get_buffer(i);
|
||||
|
||||
wolfBoot_printf("\r\n");
|
||||
wolfBoot_printf(" Public Key #%d: size %lu, type %lx, mask %08lx\r\n", i,
|
||||
size, type, mask);
|
||||
wolfBoot_printf(" Public Key #%lu: size %lu, type %lx, mask %08lx\r\n",
|
||||
(unsigned long)i, size, type, mask);
|
||||
wolfBoot_printf(" ====================================\r\n ");
|
||||
for (j = 0; j < size; j++) {
|
||||
wolfBoot_printf("%02X ", keybuf[j]);
|
||||
|
|
@ -164,6 +201,8 @@ void main(void)
|
|||
|
||||
print_info();
|
||||
|
||||
print_vector_table_info();
|
||||
|
||||
#ifdef WOLFCRYPT_TEST
|
||||
wolfBoot_printf("\r\nRunning wolfCrypt tests...\r\n");
|
||||
wolfCrypt_Init();
|
||||
|
|
|
|||
|
|
@ -582,5 +582,211 @@ void (* const IV[])(void) =
|
|||
isr_empty, // TIM8_CC_IRQ 46
|
||||
isr_empty, // DMA1_STREAM7_IRQ 47
|
||||
|
||||
|
||||
#elif defined(TARGET_va416x0) /* For Vorago VA416xx */
|
||||
/* IRQ 0 through TXEV_IRQn (195), for 212 entries. wolfBoot points VTOR
|
||||
* at this table; see docs/Targets.md for the alignment it needs. */
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
isr_empty,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef TARGET_va416x0
|
||||
/* 16 system exceptions + 196 external IRQs; see src/boot_arm.c. */
|
||||
typedef char va416x0_app_iv_len_check[
|
||||
(sizeof(IV) / sizeof(IV[0]) == 212) ? 1 : -1];
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -30,6 +30,13 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
# Select a specific probe when more than one J-Link is attached:
|
||||
# JLINK_SN=660016516 tools/scripts/va416x0/build_test.sh clean
|
||||
JLINK_SEL=""
|
||||
if [ -n "${JLINK_SN}" ]; then
|
||||
JLINK_SEL="-SelectEmuBySN ${JLINK_SN}"
|
||||
fi
|
||||
|
||||
# Function to get value from .config file
|
||||
get_config_value() {
|
||||
grep "^${1}" .config | sed -E "s/^${1}[?]?=//" | head -n1
|
||||
|
|
@ -46,15 +53,35 @@ HASH=$(get_config_value "HASH")
|
|||
SIGN_ARG="--$(echo "${SIGN}" | tr '[:upper:]' '[:lower:]')"
|
||||
HASH_ARG="--$(echo "${HASH}" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
# Common build steps
|
||||
make clean && make wolfboot.bin && make test-app/image.bin
|
||||
# Keep as separate statements: under `set -e` a failure mid `a && b` does not
|
||||
# exit, which would let a broken build sign and flash a stale image.
|
||||
make clean
|
||||
make wolfboot.bin
|
||||
make test-app/image.bin
|
||||
|
||||
# The sign tool reads several settings from the environment at run time, so
|
||||
# mirror SIGN_ENV from the top-level Makefile. Only non-empty values are
|
||||
# forwarded: sign.c uses getenv(), where an empty string is not the same as
|
||||
# unset -- ML_DSA_LEVEL="" would parse as level 0 rather than the built-in
|
||||
# default. Without ML_DSA_LEVEL an ML-DSA key is rejected with
|
||||
# "unrecognized ml-dsa key size".
|
||||
SIGN_ENV=""
|
||||
for _sign_var in ML_DSA_LEVEL IMAGE_SIGNATURE_SIZE NVM_FLASH_WRITEONCE \
|
||||
WOLFBOOT_PARTITION_UPDATE_SIZE LMS_LEVELS LMS_HEIGHT \
|
||||
LMS_WINTERNITZ XMSS_PARAMS; do
|
||||
_sign_val=$(get_config_value "${_sign_var}")
|
||||
if [ -n "${_sign_val}" ]; then
|
||||
SIGN_ENV="${SIGN_ENV} ${_sign_var}=${_sign_val}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Function to sign image
|
||||
sign_image() {
|
||||
IMAGE_HEADER_SIZE="${IMAGE_HEADER_SIZE}" \
|
||||
WOLFBOOT_PARTITION_SIZE="${PARTITION_SIZE}" \
|
||||
WOLFBOOT_SECTOR_SIZE="${SECTOR_SIZE}" \
|
||||
./tools/keytools/sign "${SIGN_ARG}" "${HASH_ARG}" test-app/image.bin wolfboot_signing_private_key.der "$1"
|
||||
env IMAGE_HEADER_SIZE="${IMAGE_HEADER_SIZE}" \
|
||||
WOLFBOOT_PARTITION_SIZE="${PARTITION_SIZE}" \
|
||||
WOLFBOOT_SECTOR_SIZE="${SECTOR_SIZE}" \
|
||||
${SIGN_ENV} \
|
||||
./tools/keytools/sign "${SIGN_ARG}" "${HASH_ARG}" test-app/image.bin wolfboot_signing_private_key.der "$1"
|
||||
}
|
||||
|
||||
# Function to print summary
|
||||
|
|
@ -72,21 +99,25 @@ print_summary() {
|
|||
|
||||
if [ "$MODE" = "clean" ]; then
|
||||
sign_image "${VERSION}"
|
||||
dd if=/dev/zero of=blank_update.bin bs=1K count=108
|
||||
# Blank the update partition so the header magic reads invalid. Exactly
|
||||
# PARTITION_SIZE bytes: rounding up would overrun the partition into swap.
|
||||
dd if=/dev/zero of=blank_update.bin bs=$((PARTITION_SIZE)) \
|
||||
count=1 2>/dev/null
|
||||
./tools/bin-assemble/bin-assemble factory.bin 0x0 wolfboot.bin \
|
||||
"${BOOT_ADDRESS}" test-app/image_v${VERSION}_signed.bin \
|
||||
"${UPDATE_ADDRESS}" blank_update.bin
|
||||
"${JLINK}" -CommanderScript tools/scripts/va416x0/flash_va416xx.jlink
|
||||
"${JLINK}" ${JLINK_SEL} -CommanderScript tools/scripts/va416x0/flash_va416xx.jlink
|
||||
print_summary
|
||||
else
|
||||
TRIGGER_ADDRESS=$(printf "0x%X" $(("${UPDATE_ADDRESS}" + "${PARTITION_SIZE}" - 5)))
|
||||
PREV_VERSION=$(("${VERSION}" - 1))
|
||||
sign_image "${PREV_VERSION}" && sign_image "${VERSION}"
|
||||
sign_image "${PREV_VERSION}"
|
||||
sign_image "${VERSION}"
|
||||
echo -n "pBOOT" > trigger_magic.bin
|
||||
./tools/bin-assemble/bin-assemble update.bin 0x0 wolfboot.bin \
|
||||
"${BOOT_ADDRESS}" test-app/image_v${PREV_VERSION}_signed.bin \
|
||||
"${UPDATE_ADDRESS}" test-app/image_v${VERSION}_signed.bin \
|
||||
"${TRIGGER_ADDRESS}" trigger_magic.bin
|
||||
"${JLINK}" -CommanderScript tools/scripts/va416x0/flash_va416xx_update.jlink
|
||||
"${JLINK}" ${JLINK_SEL} -CommanderScript tools/scripts/va416x0/flash_va416xx_update.jlink
|
||||
print_summary "${TRIGGER_ADDRESS}" "${PREV_VERSION}"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
* 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 ROM_SPI_BANK 3
|
||||
#define SPI_NUM_BANKS 4
|
||||
#define SPI_STATUS_TFE_Msk 0x01U
|
||||
#define SPI_STATUS_BUSY_Msk 0x02U
|
||||
#define SPI_FIFO_CLR_RXFIFO_Msk 0x01U
|
||||
|
|
@ -142,8 +142,11 @@ int wolfBoot_printf(const char *fmt, ...)
|
|||
|
||||
static void reset_spi_mocks(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(&mock_vor_spi, 0, sizeof(mock_vor_spi));
|
||||
mock_vor_spi.BANK[0].STATUS = SPI_STATUS_TFE_Msk;
|
||||
for (i = 0; i < SPI_NUM_BANKS; i++)
|
||||
mock_vor_spi.BANK[i].STATUS = SPI_STATUS_TFE_Msk;
|
||||
}
|
||||
|
||||
START_TEST(test_fram_write_command_failure_aborts_split_transaction)
|
||||
|
|
@ -232,12 +235,19 @@ END_TEST
|
|||
*/
|
||||
START_TEST(test_ext_flash_erase_success_fills_iram)
|
||||
{
|
||||
hal_status_t init_script[] = {
|
||||
hal_status_ok, hal_status_ok, hal_status_ok
|
||||
};
|
||||
hal_status_t ok_script[] = {
|
||||
hal_status_ok, hal_status_ok, hal_status_ok,
|
||||
hal_status_ok, hal_status_ok, hal_status_ok
|
||||
};
|
||||
int i;
|
||||
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(init_script, 3);
|
||||
ck_assert_int_eq(FRAM_Init(ROM_SPI_BANK, 0), hal_status_ok);
|
||||
|
||||
reset_spi_mocks();
|
||||
memset(g_iram, 0xA5, sizeof(g_iram));
|
||||
|
||||
|
|
@ -256,12 +266,19 @@ END_TEST
|
|||
* diag_erase in src/libwolfboot.c). */
|
||||
START_TEST(test_ext_flash_erase_failure_returns_negative)
|
||||
{
|
||||
hal_status_t init_script[] = {
|
||||
hal_status_ok, hal_status_ok, hal_status_ok
|
||||
};
|
||||
hal_status_t fail_script[] = {
|
||||
hal_status_ok, hal_status_ok, hal_status_err
|
||||
};
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(init_script, 3);
|
||||
ck_assert_int_eq(FRAM_Init(ROM_SPI_BANK, 0), hal_status_ok);
|
||||
|
||||
reset_spi_mocks();
|
||||
memset(g_iram, 0xA5, sizeof(g_iram));
|
||||
|
||||
|
|
@ -275,6 +292,150 @@ START_TEST(test_ext_flash_erase_failure_returns_negative)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
/* FRAM_Erase() must drive the bank it was handed; pre-fix it hardcoded
|
||||
* ROM_SPI_BANK. FRAM_WaitIdle() clears that bank's FIFO, so it is visible. */
|
||||
START_TEST(test_fram_erase_uses_requested_bank)
|
||||
{
|
||||
hal_status_t init_script[] = {
|
||||
hal_status_ok, hal_status_ok, hal_status_ok
|
||||
};
|
||||
hal_status_t ok_script[] = {
|
||||
hal_status_ok, hal_status_ok, hal_status_ok
|
||||
};
|
||||
|
||||
reset_spi_mocks();
|
||||
|
||||
/* Bind the driver to bank 1, not the default ROM_SPI_BANK. */
|
||||
set_transmit_script(init_script, 3);
|
||||
ck_assert_int_eq(FRAM_Init(1, 0), hal_status_ok);
|
||||
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(ok_script, 3);
|
||||
ck_assert_int_eq(FRAM_Erase(1, 0x40, 32), hal_status_ok);
|
||||
|
||||
ck_assert_uint_eq(mock_vor_spi.BANK[1].FIFO_CLR,
|
||||
SPI_FIFO_CLR_RXFIFO_Msk | SPI_FIFO_CLR_TXFIFO_Msk);
|
||||
ck_assert_uint_eq(mock_vor_spi.BANK[ROM_SPI_BANK].FIFO_CLR, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* One device at a time: a bank other than the one FRAM_Init() bound to must
|
||||
* be rejected, not drained while transmitting on the init handle's bank. */
|
||||
START_TEST(test_fram_rejects_bank_other_than_initialized)
|
||||
{
|
||||
hal_status_t init_script[] = {
|
||||
hal_status_ok, hal_status_ok, hal_status_ok
|
||||
};
|
||||
uint8_t buf[4] = { 1, 2, 3, 4 };
|
||||
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(init_script, 3);
|
||||
ck_assert_int_eq(FRAM_Init(1, 0), hal_status_ok);
|
||||
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(init_script, 0);
|
||||
ck_assert_int_eq(FRAM_Write(2, 0x40, buf, sizeof(buf)),
|
||||
hal_status_badParam);
|
||||
ck_assert_int_eq(FRAM_Read(2, 0x40, buf, sizeof(buf)),
|
||||
hal_status_badParam);
|
||||
/* No SPI traffic at all on a rejected request. */
|
||||
ck_assert_int_eq(transmit_call_count, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* FRAM_Init() must bounds check spiBank before indexing BANK[], as
|
||||
* FRAM_WaitIdle() already did. */
|
||||
START_TEST(test_fram_init_rejects_out_of_range_bank)
|
||||
{
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(NULL, 0);
|
||||
ck_assert_int_eq(FRAM_Init(SPI_NUM_BANKS, 0), hal_status_badParam);
|
||||
ck_assert_int_eq(transmit_call_count, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* NULL buffer and zero length must be rejected before any SPI traffic. */
|
||||
START_TEST(test_fram_rejects_null_buffer_and_zero_length)
|
||||
{
|
||||
hal_status_t init_script[] = {
|
||||
hal_status_ok, hal_status_ok, hal_status_ok
|
||||
};
|
||||
uint8_t buf[4] = { 0 };
|
||||
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(init_script, 3);
|
||||
ck_assert_int_eq(FRAM_Init(ROM_SPI_BANK, 0), hal_status_ok);
|
||||
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(init_script, 0);
|
||||
ck_assert_int_eq(FRAM_Write(ROM_SPI_BANK, 0x40, NULL, 4),
|
||||
hal_status_badParam);
|
||||
ck_assert_int_eq(FRAM_Write(ROM_SPI_BANK, 0x40, buf, 0),
|
||||
hal_status_badParam);
|
||||
ck_assert_int_eq(FRAM_Read(ROM_SPI_BANK, 0x40, NULL, 4),
|
||||
hal_status_badParam);
|
||||
ck_assert_int_eq(FRAM_Read(ROM_SPI_BANK, 0x40, buf, 0),
|
||||
hal_status_badParam);
|
||||
ck_assert_int_eq(transmit_call_count, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* addr 0xFFFFFFF0 leaves 15 bytes, so a 32 byte request must be rejected.
|
||||
* The pre-fix `(addr + len) > FRAM_SIZE` wrapped to 0x10 and allowed it. */
|
||||
START_TEST(test_fram_bounds_check_survives_address_wrap)
|
||||
{
|
||||
hal_status_t init_script[] = {
|
||||
hal_status_ok, hal_status_ok, hal_status_ok
|
||||
};
|
||||
uint8_t buf[32] = { 0 };
|
||||
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(init_script, 3);
|
||||
ck_assert_int_eq(FRAM_Init(ROM_SPI_BANK, 0), hal_status_ok);
|
||||
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(init_script, 0);
|
||||
ck_assert_int_eq(
|
||||
FRAM_Write(ROM_SPI_BANK, 0xFFFFFFF0U, buf, sizeof(buf)),
|
||||
hal_status_badParam);
|
||||
ck_assert_int_eq(
|
||||
FRAM_Read(ROM_SPI_BANK, 0xFFFFFFF0U, buf, sizeof(buf)),
|
||||
hal_status_badParam);
|
||||
ck_assert_int_eq(transmit_call_count, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* A failed FRAM_Init() must not bind the bank: doing so would let a later
|
||||
* transfer through the gate onto an incompletely initialized handle. */
|
||||
START_TEST(test_failed_init_does_not_bind_bank)
|
||||
{
|
||||
hal_status_t ok_script[] = {
|
||||
hal_status_ok, hal_status_ok, hal_status_ok
|
||||
};
|
||||
hal_status_t fail_script[] = { hal_status_err };
|
||||
uint8_t buf[4] = { 1, 2, 3, 4 };
|
||||
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(ok_script, 3);
|
||||
ck_assert_int_eq(FRAM_Init(ROM_SPI_BANK, 0), hal_status_ok);
|
||||
|
||||
/* Now fail an init on a different bank. */
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(fail_script, 1);
|
||||
ck_assert_int_ne(FRAM_Init(1, 0), hal_status_ok);
|
||||
|
||||
/* The failed init leaves spiHandle pointing at bank 1, so the gate must
|
||||
* close entirely rather than keep naming ROM_SPI_BANK. */
|
||||
reset_spi_mocks();
|
||||
set_transmit_script(fail_script, 0);
|
||||
ck_assert_int_eq(FRAM_Write(1, 0x40, buf, sizeof(buf)),
|
||||
hal_status_badParam);
|
||||
ck_assert_int_eq(FRAM_Write(ROM_SPI_BANK, 0x40, buf, sizeof(buf)),
|
||||
hal_status_badParam);
|
||||
ck_assert_int_eq(transmit_call_count, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *va416x0_fram_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("va416x0-fram");
|
||||
|
|
@ -285,6 +446,12 @@ Suite *va416x0_fram_suite(void)
|
|||
tcase_add_test(tc, test_iram_fill_unaligned_64bit_addr);
|
||||
tcase_add_test(tc, test_ext_flash_erase_success_fills_iram);
|
||||
tcase_add_test(tc, test_ext_flash_erase_failure_returns_negative);
|
||||
tcase_add_test(tc, test_fram_erase_uses_requested_bank);
|
||||
tcase_add_test(tc, test_fram_rejects_bank_other_than_initialized);
|
||||
tcase_add_test(tc, test_fram_init_rejects_out_of_range_bank);
|
||||
tcase_add_test(tc, test_fram_rejects_null_buffer_and_zero_length);
|
||||
tcase_add_test(tc, test_fram_bounds_check_survives_address_wrap);
|
||||
tcase_add_test(tc, test_failed_init_does_not_bind_bank);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
|
|
|
|||
Loading…
Reference in New Issue