watchdog: add generic feed hook and RX driver

pull/845/head
David Garske 2026-07-24 08:40:34 -07:00 committed by Daniele Lacamera
parent eaa39be9e4
commit d073ae4ddb
9 changed files with 74 additions and 1 deletions

View File

@ -54,3 +54,7 @@ PKA?=0
# Location of reset entry point from start of flash
#CFLAGS_EXTRA+=-DBOOT_ENTRY_OFFSET=0x2C
# External watchdog (e.g. MAX6316-MAX6322): toggle WDI from wolfBoot's long
# loops. WATCHDOG_WDI_PORT = RX port, WATCHDOG_WDI_PIN = bit (see renesas-rx.c).
#CFLAGS_EXTRA+=-DWATCHDOG -DWATCHDOG_WDI_PORT=0 -DWATCHDOG_WDI_PIN=5

View File

@ -54,3 +54,7 @@ PKA?=0
# Location of reset entry point from start of flash
#CFLAGS_EXTRA+=-DBOOT_ENTRY_OFFSET=0x2C
# External watchdog (e.g. MAX6316-MAX6322): toggle WDI from wolfBoot's long
# loops. WATCHDOG_WDI_PORT = RX port, WATCHDOG_WDI_PIN = bit (see renesas-rx.c).
#CFLAGS_EXTRA+=-DWATCHDOG -DWATCHDOG_WDI_PORT=0 -DWATCHDOG_WDI_PIN=5

View File

@ -203,6 +203,17 @@ The key needed for the firmware signing tool is the 32 byte AES Key + 16 byte IV
| RX65N | 120MHz | ECDSA Verify P256 | 2.95 ms | 1208 ms | 602 ms | 517 ms |
## RX External Watchdog (MAX6316-MAX6322)
An external windowed watchdog resets the MCU unless its `WDI` input sees an edge each timeout period, which image verification or a swap can exceed. Build with `WATCHDOG` and point it at the GPIO wired to `WDI`:
```
CFLAGS_EXTRA+=-DWATCHDOG -DWATCHDOG_WDI_PORT=0 -DWATCHDOG_WDI_PIN=5
```
`WATCHDOG_WDI_PORT` is the RX port number and `WATCHDOG_WDI_PIN` the bit (0-7). wolfBoot calls `wolfBoot_watchdog_feed()` from its hash and flash copy/erase loops; the RX HAL toggles `WDI` to restart the timer. The application must keep servicing `WDI` after boot. `wolfBoot_watchdog_feed()` is a weak no-op by default (`include/hal.h`), so any port can override it for a different watchdog.
## RX Production Protection (recommendations)
1) Lockdown external serial programmer `SPCC.SPE = 0`

View File

@ -6765,7 +6765,7 @@ The following build options are available for the S32K1xx HAL:
| `RAM_CODE` | **Required for S32K1xx.** Run flash operations from RAM (no read-while-write on same block). |
| `WOLFBOOT_RESTORE_CLOCK` | Restore clock to SIRC (8 MHz) before booting application. Recommended for applications that configure their own clocks. |
| `WOLFBOOT_DISABLE_WATCHDOG_ON_BOOT` | Keep watchdog disabled when jumping to application. By default, the watchdog is re-enabled before boot since it is enabled out of reset. |
| `WATCHDOG` | Enable watchdog during wolfBoot operation. Recommended for production. |
| `WATCHDOG` | Enable the watchdog during wolfBoot operation. wolfBoot calls `wolfBoot_watchdog_feed()` from its hash and copy/erase loops -- a weak no-op a port overrides to service its watchdog (e.g. external MAX6316-MAX6322, see `hal/renesas-rx.c`). |
| `WATCHDOG_TIMEOUT_MS` | Watchdog timeout in milliseconds when `WATCHDOG` is enabled (default: 1000ms). |
| `S32K1XX_CLOCK_HSRUN` | Enable HSRUN mode (112 MHz). Requires external crystal and SPLL (not fully implemented). |
| `DEBUG_UART` | Enable LPUART1 debug output. |

View File

@ -472,6 +472,31 @@ int hal_renesas_init(void)
#endif /* TSIP */
#ifdef WATCHDOG
/* External watchdog (e.g. MAX6316-MAX6322): toggle the WDI GPIO so a signal
* edge restarts its timer. Pin set by WATCHDOG_WDI_PORT/WATCHDOG_WDI_PIN. */
#ifndef WATCHDOG_WDI_PORT
#define WATCHDOG_WDI_PORT 0 /* PORT0 */
#endif
#ifndef WATCHDOG_WDI_PIN
#define WATCHDOG_WDI_PIN 0
#endif
static void hal_watchdog_init(void)
{
/* Drive WDI as a general-purpose CMOS output */
PORT_PMR(WATCHDOG_WDI_PORT) &= (uint8_t)~(1U << WATCHDOG_WDI_PIN);
PORT_PDR(WATCHDOG_WDI_PORT) |= (uint8_t) (1U << WATCHDOG_WDI_PIN);
}
/* RAMFUNCTION: callable from the RAM-resident flash paths. */
void RAMFUNCTION wolfBoot_watchdog_feed(void)
{
/* Toggle WDI: any transition restarts the external watchdog timer */
PORT_PODR(WATCHDOG_WDI_PORT) ^= (uint8_t)(1U << WATCHDOG_WDI_PIN);
}
#endif /* WATCHDOG */
void hal_init(void)
{
#if defined(WOLFBOOT_RENESAS_TSIP) && !defined(WOLFBOOT_RENESAS_APP)
@ -494,6 +519,10 @@ void hal_init(void)
hal_flash_init();
#ifdef WATCHDOG
hal_watchdog_init();
#endif
#if defined(WOLFBOOT_RENESAS_TSIP) && !defined(WOLFBOOT_RENESAS_APP)
err = hal_renesas_init();
if (err != 0) {

View File

@ -119,6 +119,15 @@ void hal_prepare_boot(void);
const char* hal_fit_config_name(void);
#endif
/* Optional watchdog kick. With -DWATCHDOG, wolfBoot calls this from its long
* hash and flash copy/erase loops; a port overrides the weak no-op default
* (see libwolfboot.c, hal/renesas-rx.c). Compiles out when WATCHDOG is unset. */
#ifdef WATCHDOG
void wolfBoot_watchdog_feed(void);
#else
#define wolfBoot_watchdog_feed() do {} while (0)
#endif
/* FPGA load mode constants + hal_fpga_load() prototype (kept in a standalone
* header so the per-target HAL .c files can include just this, not all of
* hal.h). Gated internally by WOLFBOOT_FPGA_BITSTREAM. */

View File

@ -1094,6 +1094,7 @@ static int image_sha256(struct wolfBoot_image *img, uint8_t *hash)
blksz = img->fw_size - position;
wc_Sha256Update(&sha256_ctx, p, blksz);
position += blksz;
wolfBoot_watchdog_feed();
} while (position < img->fw_size);
}
#endif
@ -1205,6 +1206,7 @@ static int image_sha384(struct wolfBoot_image *img, uint8_t *hash)
blksz = img->fw_size - position;
wc_Sha384Update(&sha384_ctx, p, blksz);
position += blksz;
wolfBoot_watchdog_feed();
} while (position < img->fw_size);
}
#endif
@ -1322,6 +1324,7 @@ static int image_sha3_384(struct wolfBoot_image *img, uint8_t *hash)
blksz = img->fw_size - position;
wc_Sha3_384_Update(&sha3_ctx, p, blksz);
position += blksz;
wolfBoot_watchdog_feed();
} while (position < img->fw_size);
}
#endif

View File

@ -32,6 +32,15 @@
#include "image.h"
#include "printf.h"
#ifdef WATCHDOG
/* Weak no-op default; a port HAL overrides this to service the watchdog.
* RAMFUNCTION so the fallback is safe when called from the RAM-resident flash
* paths (update_flash.c) on RAM_CODE targets. */
void RAMFUNCTION WEAKFUNCTION wolfBoot_watchdog_feed(void)
{
}
#endif
#ifdef UNIT_TEST
/**
* @def unit_dbg

View File

@ -279,6 +279,9 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src,
wolfBoot_printf("Copy sector %d (part %d->%d)\n",
sector, src->part, dst->part);
/* Kick the watchdog once per sector copy (no-op unless -DWATCHDOG) */
wolfBoot_watchdog_feed();
if (src->part == PART_SWAP)
src_sector_offset = 0;
if (dst->part == PART_SWAP)
@ -1213,6 +1216,7 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
) {
wb_flash_erase(&boot, sector * sector_size, sector_size);
wb_flash_erase(&update, sector * sector_size, sector_size);
wolfBoot_watchdog_feed();
sector++;
}
#endif /* WOLFBOOT_FLASH_MULTI_SECTOR_ERASE */