From 1254cc7a6a2c97fc9098ae58e59b87dc730888db Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Sun, 4 Oct 2026 21:23:29 -0400 Subject: [PATCH 01/18] [stm32wba_aes, stm32n6_cryp] Split WBA AES from WB, fix CRYP AAD flow control - WBA/U5 AES: own driver; CCF via ISR/ICR, wait for KEYVALID, two-step ECB/CBC decrypt key prep, KEIF-safe key zeroing - N6 CRYP: poll IFNF before each AAD block, KERF-safe key zeroing --- boards/stm32u5a5zj_nucleo/wolfHAL_board.h | 10 +- boards/stm32wba55cg_nucleo/wolfHAL_board.h | 22 +- src/crypto/stm32n6_cryp.c | 16 + src/crypto/stm32u5_aes.c | 16 +- src/crypto/stm32wba_aes.c | 1770 +++++++++++++++++++- wolfHAL/crypto/stm32u5_aes.h | 58 +- wolfHAL/crypto/stm32wba_aes.h | 448 ++++- 7 files changed, 2238 insertions(+), 102 deletions(-) diff --git a/boards/stm32u5a5zj_nucleo/wolfHAL_board.h b/boards/stm32u5a5zj_nucleo/wolfHAL_board.h index 8052714..a9f412b 100644 --- a/boards/stm32u5a5zj_nucleo/wolfHAL_board.h +++ b/boards/stm32u5a5zj_nucleo/wolfHAL_board.h @@ -80,9 +80,9 @@ enum { }, \ } -/* AES + mode dev initializers — singletons defined in stm32wb_aes.c - * (stm32u5 alias points at stm32wb leaf). Mutable GCM/CCM state buffers - * (g_stm32wbAesGcm/CcmDevState) are static in the driver TU. */ +/* AES + mode dev initializers — singletons defined in stm32wba_aes.c + * (stm32u5 alias points at stm32wba leaf). Mutable GCM/CCM state buffers + * (g_stm32wbaAesGcm/CcmDevState) are static in the driver TU. */ #define WHAL_CFG_STM32U5_AES_DEV { \ .base = WHAL_STM32U5A5_AES_BASE, \ .cfg = (void *)&(const whal_Stm32u5_Aes_Cfg){ \ @@ -104,7 +104,7 @@ enum { #define WHAL_CFG_STM32U5_AES_GCM_DEV { \ .crypto = (whal_Crypto *)&whal_Stm32u5_Aes_Dev, \ - .state = &g_stm32wbAesGcmDevState, \ + .state = &g_stm32wbaAesGcmDevState, \ } #define WHAL_CFG_STM32U5_AES_GMAC_DEV { \ @@ -113,7 +113,7 @@ enum { #define WHAL_CFG_STM32U5_AES_CCM_DEV { \ .crypto = (whal_Crypto *)&whal_Stm32u5_Aes_Dev, \ - .state = &g_stm32wbAesCcmDevState, \ + .state = &g_stm32wbaAesCcmDevState, \ } /* RNG dev initializer — singleton defined in stm32wba_rng.c (alias). */ diff --git a/boards/stm32wba55cg_nucleo/wolfHAL_board.h b/boards/stm32wba55cg_nucleo/wolfHAL_board.h index 20ddd68..23a96f6 100644 --- a/boards/stm32wba55cg_nucleo/wolfHAL_board.h +++ b/boards/stm32wba55cg_nucleo/wolfHAL_board.h @@ -81,9 +81,9 @@ enum { }, \ } -/* AES + mode dev initializers — singletons defined in stm32wb_aes.c - * (stm32wba is an include alias). Mutable GCM/CCM state buffers - * (g_stm32wbAesGcm/CcmDevState) are static in the driver TU. */ +/* AES + mode dev initializers — singletons defined in stm32wba_aes.c. + * Mutable GCM/CCM state buffers (g_stm32wbaAesGcm/CcmDevState) are static + * in the driver TU. */ #define WHAL_CFG_STM32WBA_AES_DEV { \ .base = WHAL_STM32WBA55_AES_BASE, \ .cfg = (void *)&(const whal_Stm32wba_Aes_Cfg){ \ @@ -92,29 +92,29 @@ enum { } #define WHAL_CFG_STM32WBA_AES_ECB_DEV { \ - .crypto = (whal_Crypto *)&whal_Stm32wb_Aes_Dev, \ + .crypto = (whal_Crypto *)&whal_Stm32wba_Aes_Dev, \ } #define WHAL_CFG_STM32WBA_AES_CBC_DEV { \ - .crypto = (whal_Crypto *)&whal_Stm32wb_Aes_Dev, \ + .crypto = (whal_Crypto *)&whal_Stm32wba_Aes_Dev, \ } #define WHAL_CFG_STM32WBA_AES_CTR_DEV { \ - .crypto = (whal_Crypto *)&whal_Stm32wb_Aes_Dev, \ + .crypto = (whal_Crypto *)&whal_Stm32wba_Aes_Dev, \ } #define WHAL_CFG_STM32WBA_AES_GCM_DEV { \ - .crypto = (whal_Crypto *)&whal_Stm32wb_Aes_Dev, \ - .state = &g_stm32wbAesGcmDevState, \ + .crypto = (whal_Crypto *)&whal_Stm32wba_Aes_Dev, \ + .state = &g_stm32wbaAesGcmDevState, \ } #define WHAL_CFG_STM32WBA_AES_GMAC_DEV { \ - .crypto = (whal_Crypto *)&whal_Stm32wb_Aes_Dev, \ + .crypto = (whal_Crypto *)&whal_Stm32wba_Aes_Dev, \ } #define WHAL_CFG_STM32WBA_AES_CCM_DEV { \ - .crypto = (whal_Crypto *)&whal_Stm32wb_Aes_Dev, \ - .state = &g_stm32wbAesCcmDevState, \ + .crypto = (whal_Crypto *)&whal_Stm32wba_Aes_Dev, \ + .state = &g_stm32wbaAesCcmDevState, \ } /* RNG dev initializer — singleton defined in stm32wba_rng.c. */ diff --git a/src/crypto/stm32n6_cryp.c b/src/crypto/stm32n6_cryp.c index 5562da5..6b1f3f6 100644 --- a/src/crypto/stm32n6_cryp.c +++ b/src/crypto/stm32n6_cryp.c @@ -197,6 +197,10 @@ static void WriteIv16(size_t base, const uint8_t *iv) static void ZeroKeyIv(size_t base) { + /* KEYSIZE must cover K0LR..K3RR or the write sequence raises KERF */ + whal_Reg_Update(base, CRYP_CR_REG, CRYP_CR_KEYSIZE_Msk, + whal_SetBits(CRYP_CR_KEYSIZE_Msk, CRYP_CR_KEYSIZE_Pos, + CRYP_KEYSIZE_256)); whal_Reg_Write(base, CRYP_K0LR_REG, 0); whal_Reg_Write(base, CRYP_K0RR_REG, 0); whal_Reg_Write(base, CRYP_K1LR_REG, 0); @@ -755,6 +759,10 @@ static whal_Error GcmHeaderPhase(const uint8_t *aad, size_t aadSz) for (i = 0; i < aadSz; i += 16) { size_t remain = aadSz - i; + err = whal_Reg_ReadPoll(base, CRYP_SR_REG, CRYP_SR_IFNF_Msk, + CRYP_SR_IFNF_Msk, cfg->timeout); + if (err) + return err; if (remain >= 16) { WriteBlock(base, aad + i); } else { @@ -1285,6 +1293,10 @@ whal_Error whal_Stm32n6_CrypAesCcm_Oneshot(whal_AesCcm *dev, size_t j; for (j = 0; j < 16 && aadOff < aadSz; j++) blk[j] = aadPtr[aadOff++]; + err = whal_Reg_ReadPoll(base, CRYP_SR_REG, CRYP_SR_IFNF_Msk, + CRYP_SR_IFNF_Msk, cfg->timeout); + if (err) + goto cleanup; WriteBlock(base, blk); } @@ -1453,6 +1465,10 @@ whal_Error whal_Stm32n6_CrypAesCcm_Start(whal_AesCcm *dev, size_t j; for (j = 0; j < 16 && aadOff < aadSz; j++) blk[j] = aadPtr[aadOff++]; + err = whal_Reg_ReadPoll(base, CRYP_SR_REG, CRYP_SR_IFNF_Msk, + CRYP_SR_IFNF_Msk, cfg->timeout); + if (err) + goto cleanup; WriteBlock(base, blk); } diff --git a/src/crypto/stm32u5_aes.c b/src/crypto/stm32u5_aes.c index d4232a7..0912c86 100644 --- a/src/crypto/stm32u5_aes.c +++ b/src/crypto/stm32u5_aes.c @@ -20,24 +20,24 @@ */ #ifdef WHAL_CFG_STM32U5_AES_INIT_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_INIT_DIRECT_API_MAPPING +#define WHAL_CFG_STM32WBA_AES_INIT_DIRECT_API_MAPPING #endif #ifdef WHAL_CFG_STM32U5_AES_ECB_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_ECB_DIRECT_API_MAPPING +#define WHAL_CFG_STM32WBA_AES_ECB_DIRECT_API_MAPPING #endif #ifdef WHAL_CFG_STM32U5_AES_CBC_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_CBC_DIRECT_API_MAPPING +#define WHAL_CFG_STM32WBA_AES_CBC_DIRECT_API_MAPPING #endif #ifdef WHAL_CFG_STM32U5_AES_CTR_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_CTR_DIRECT_API_MAPPING +#define WHAL_CFG_STM32WBA_AES_CTR_DIRECT_API_MAPPING #endif #ifdef WHAL_CFG_STM32U5_AES_GCM_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_GCM_DIRECT_API_MAPPING +#define WHAL_CFG_STM32WBA_AES_GCM_DIRECT_API_MAPPING #endif #ifdef WHAL_CFG_STM32U5_AES_GMAC_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_GMAC_DIRECT_API_MAPPING +#define WHAL_CFG_STM32WBA_AES_GMAC_DIRECT_API_MAPPING #endif #ifdef WHAL_CFG_STM32U5_AES_CCM_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_CCM_DIRECT_API_MAPPING +#define WHAL_CFG_STM32WBA_AES_CCM_DIRECT_API_MAPPING #endif -#include "stm32wb_aes.c" +#include "stm32wba_aes.c" diff --git a/src/crypto/stm32wba_aes.c b/src/crypto/stm32wba_aes.c index 7410928..593f19a 100644 --- a/src/crypto/stm32wba_aes.c +++ b/src/crypto/stm32wba_aes.c @@ -19,27 +19,1779 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -/* Forward STM32WBA AES direct API mapping flags to STM32WB */ +#include +#include "wolfHAL_board.h" /* provides WHAL_CFG_STM32WBA_AES*_DEV initializers */ +#include +#include +#include +#include +#include +#include + +/* Mutable state buffers for GCM/CCM streaming sessions. Internal linkage — + * referenced only by the AesGcm/AesCcm singletons below. */ +static whal_Stm32wba_AesGcm_State g_stm32wbaAesGcmDevState; +static whal_Stm32wba_AesCcm_State g_stm32wbaAesCcmDevState; + +const whal_Crypto whal_Stm32wba_Aes_Dev = WHAL_CFG_STM32WBA_AES_DEV; +const whal_AesEcb whal_Stm32wba_AesEcb_Dev = WHAL_CFG_STM32WBA_AES_ECB_DEV; +const whal_AesCbc whal_Stm32wba_AesCbc_Dev = WHAL_CFG_STM32WBA_AES_CBC_DEV; +const whal_AesCtr whal_Stm32wba_AesCtr_Dev = WHAL_CFG_STM32WBA_AES_CTR_DEV; +const whal_AesGcm whal_Stm32wba_AesGcm_Dev = WHAL_CFG_STM32WBA_AES_GCM_DEV; +const whal_AesGmac whal_Stm32wba_AesGmac_Dev = WHAL_CFG_STM32WBA_AES_GMAC_DEV; +const whal_AesCcm whal_Stm32wba_AesCcm_Dev = WHAL_CFG_STM32WBA_AES_CCM_DEV; + +/* Control Register */ +#define AES_CR_REG 0x00 +#define AES_CR_EN_Pos 0 +#define AES_CR_EN_Msk (1UL << AES_CR_EN_Pos) + +#define AES_CR_DATATYPE_Pos 1 +#define AES_CR_DATATYPE_Msk (3UL << AES_CR_DATATYPE_Pos) + +#define AES_CR_MODE_Pos 3 +#define AES_CR_MODE_Msk (3UL << AES_CR_MODE_Pos) + +#define AES_CR_CHMOD_Pos 5 +#define AES_CR_CHMOD_Msk (3UL << AES_CR_CHMOD_Pos) + +#define AES_CR_CHMOD2_Pos 16 +#define AES_CR_CHMOD2_Msk (1UL << AES_CR_CHMOD2_Pos) + +#define AES_CR_KEYSIZE_Pos 18 +#define AES_CR_KEYSIZE_Msk (1UL << AES_CR_KEYSIZE_Pos) + +#define AES_CR_GCMPH_Pos 13 +#define AES_CR_GCMPH_Msk (3UL << AES_CR_GCMPH_Pos) + +#define AES_CR_NPBLB_Pos 20 +#define AES_CR_NPBLB_Msk (0xF << AES_CR_NPBLB_Pos) + +/* Status Register */ +#define AES_SR_REG 0x04 +#define AES_SR_RDERRF_Pos 1 +#define AES_SR_RDERRF_Msk (1UL << AES_SR_RDERRF_Pos) + +#define AES_SR_WRERRF_Pos 2 +#define AES_SR_WRERRF_Msk (1UL << AES_SR_WRERRF_Pos) + +#define AES_SR_KEYVALID_Pos 7 +#define AES_SR_KEYVALID_Msk (1UL << AES_SR_KEYVALID_Pos) + +/* Data Registers */ +#define AES_DINR_REG 0x08 +#define AES_DOUTR_REG 0x0C + +/* Key Registers */ +#define AES_KEYR0_REG 0x10 +#define AES_KEYR1_REG 0x14 +#define AES_KEYR2_REG 0x18 +#define AES_KEYR3_REG 0x1C +#define AES_KEYR4_REG 0x30 +#define AES_KEYR5_REG 0x34 +#define AES_KEYR6_REG 0x38 +#define AES_KEYR7_REG 0x3C + +/* Initialization Vector Registers */ +#define AES_IVR0_REG 0x20 +#define AES_IVR1_REG 0x24 +#define AES_IVR2_REG 0x28 +#define AES_IVR3_REG 0x2C + +/* Interrupt Status Register */ +#define AES_ISR_REG 0x304 +#define AES_ISR_CCF_Pos 0 +#define AES_ISR_CCF_Msk (1UL << AES_ISR_CCF_Pos) + +/* Interrupt Clear Register */ +#define AES_ICR_REG 0x308 +#define AES_ICR_CCF_Pos 0 +#define AES_ICR_CCF_Msk (1UL << AES_ICR_CCF_Pos) + +#define AES_ICR_KEIF_Pos 2 +#define AES_ICR_KEIF_Msk (1UL << AES_ICR_KEIF_Pos) + +/* Chaining modes */ +#define AES_CHMOD_ECB 0x0 +#define AES_CHMOD_CBC 0x1 +#define AES_CHMOD_CTR 0x2 +#define AES_CHMOD_GCM 0x3 +#define AES_CHMOD_CCM 0x4 + +/* Operating modes */ +#define AES_MODE_ENCRYPT 0x0 +#define AES_MODE_KEYPREP 0x1 +#define AES_MODE_DECRYPT 0x2 + +/* Data types (swap modes) */ +#define AES_DATATYPE_NONE 0x0 +#define AES_DATATYPE_HALFWORD 0x1 +#define AES_DATATYPE_BYTE 0x2 +#define AES_DATATYPE_BIT 0x3 + +/* GCM phases */ +#define AES_GCMPH_INIT 0x0 +#define AES_GCMPH_HEADER 0x1 +#define AES_GCMPH_PAYLOAD 0x2 +#define AES_GCMPH_FINAL 0x3 + +static void WriteKey(size_t base, const uint8_t *key, size_t keySz) +{ + const uint8_t *k = key; + if (keySz == 32) { + whal_Reg_Write(base, AES_KEYR7_REG, whal_LoadBe32(k)); + whal_Reg_Write(base, AES_KEYR6_REG, whal_LoadBe32(k + 4)); + whal_Reg_Write(base, AES_KEYR5_REG, whal_LoadBe32(k + 8)); + whal_Reg_Write(base, AES_KEYR4_REG, whal_LoadBe32(k + 12)); + k += 16; + } + whal_Reg_Write(base, AES_KEYR3_REG, whal_LoadBe32(k)); + whal_Reg_Write(base, AES_KEYR2_REG, whal_LoadBe32(k + 4)); + whal_Reg_Write(base, AES_KEYR1_REG, whal_LoadBe32(k + 8)); + whal_Reg_Write(base, AES_KEYR0_REG, whal_LoadBe32(k + 12)); +} + +static void WriteIv(size_t base, const uint8_t *iv) +{ + whal_Reg_Write(base, AES_IVR3_REG, whal_LoadBe32(iv)); + whal_Reg_Write(base, AES_IVR2_REG, whal_LoadBe32(iv + 4)); + whal_Reg_Write(base, AES_IVR1_REG, whal_LoadBe32(iv + 8)); + whal_Reg_Write(base, AES_IVR0_REG, whal_LoadBe32(iv + 12)); +} + +/* Wipe key and IV/counter material from the peripheral registers. Callers must + * clear EN first (key registers are only writable while disabled). */ +static void ZeroKeyIv(size_t base) +{ + /* KEYSIZE must cover all eight key registers or the write sequence raises KEIF */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Msk); + whal_Reg_Write(base, AES_KEYR7_REG, 0); + whal_Reg_Write(base, AES_KEYR6_REG, 0); + whal_Reg_Write(base, AES_KEYR5_REG, 0); + whal_Reg_Write(base, AES_KEYR4_REG, 0); + whal_Reg_Write(base, AES_KEYR3_REG, 0); + whal_Reg_Write(base, AES_KEYR2_REG, 0); + whal_Reg_Write(base, AES_KEYR1_REG, 0); + whal_Reg_Write(base, AES_KEYR0_REG, 0); + whal_Reg_Write(base, AES_IVR3_REG, 0); + whal_Reg_Write(base, AES_IVR2_REG, 0); + whal_Reg_Write(base, AES_IVR1_REG, 0); + whal_Reg_Write(base, AES_IVR0_REG, 0); +} + +static void WriteBlock(size_t base, const uint8_t *in) +{ + whal_Reg_Write(base, AES_DINR_REG, whal_LoadBe32(in)); + whal_Reg_Write(base, AES_DINR_REG, whal_LoadBe32(in + 4)); + whal_Reg_Write(base, AES_DINR_REG, whal_LoadBe32(in + 8)); + whal_Reg_Write(base, AES_DINR_REG, whal_LoadBe32(in + 12)); +} + +static void ReadBlock(size_t base, uint8_t *out) +{ + whal_StoreBe32(out, whal_Reg_Read(base, AES_DOUTR_REG)); + whal_StoreBe32(out + 4, whal_Reg_Read(base, AES_DOUTR_REG)); + whal_StoreBe32(out + 8, whal_Reg_Read(base, AES_DOUTR_REG)); + whal_StoreBe32(out + 12, whal_Reg_Read(base, AES_DOUTR_REG)); +} + +static whal_Error WaitForCCF(size_t base, whal_Timeout *timeout) +{ + whal_Error err; + err = whal_Reg_ReadPoll(base, AES_ISR_REG, AES_ISR_CCF_Msk, + AES_ISR_CCF_Msk, timeout); + if (err) + return err; + whal_Reg_Write(base, AES_ICR_REG, AES_ICR_CCF_Msk); + return WHAL_SUCCESS; +} + +/* Write the key and wait for KEYVALID. KEYSIZE must already be programmed. */ +static inline whal_Error LoadKey(size_t base, const uint8_t *key, size_t keySz, + whal_Timeout *timeout) +{ + whal_Reg_Write(base, AES_ICR_REG, AES_ICR_KEIF_Msk); + WriteKey(base, key, keySz); + return whal_Reg_ReadPoll(base, AES_SR_REG, AES_SR_KEYVALID_Msk, + AES_SR_KEYVALID_Msk, timeout); +} + +static whal_Error ProcessBlockCipher(whal_Crypto *cryptoDev, + const uint8_t *in, uint8_t *out, + size_t sz) +{ + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)cryptoDev->cfg; + size_t base = cryptoDev->base; + whal_Error err; + size_t i; + + if (sz == 0) + return WHAL_SUCCESS; + + if (!in || !out || (sz & 0xF) != 0) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + + for (i = 0; i < sz; i += 16) { + WriteBlock(base, in + i); + err = WaitForCCF(base, cfg->timeout); + if (err) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return err; + } + ReadBlock(base, out + i); + } + + return WHAL_SUCCESS; +} + +static void DisableAes(whal_Crypto *cryptoDev) +{ + whal_Reg_Update(cryptoDev->base, AES_CR_REG, AES_CR_EN_Msk, 0); +} + + +/* ---- Direct API mapping ---- */ + #ifdef WHAL_CFG_STM32WBA_AES_INIT_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_INIT_DIRECT_API_MAPPING +#define whal_Stm32wba_Aes_Init whal_Crypto_Init +#define whal_Stm32wba_Aes_Deinit whal_Crypto_Deinit #endif #ifdef WHAL_CFG_STM32WBA_AES_ECB_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_ECB_DIRECT_API_MAPPING +#define whal_Stm32wba_AesEcb_Oneshot whal_AesEcb_Oneshot +#define whal_Stm32wba_AesEcb_Start whal_AesEcb_Start +#define whal_Stm32wba_AesEcb_Process whal_AesEcb_Process #endif #ifdef WHAL_CFG_STM32WBA_AES_CBC_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_CBC_DIRECT_API_MAPPING +#define whal_Stm32wba_AesCbc_Oneshot whal_AesCbc_Oneshot +#define whal_Stm32wba_AesCbc_Start whal_AesCbc_Start +#define whal_Stm32wba_AesCbc_Process whal_AesCbc_Process #endif #ifdef WHAL_CFG_STM32WBA_AES_CTR_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_CTR_DIRECT_API_MAPPING +#define whal_Stm32wba_AesCtr_Oneshot whal_AesCtr_Oneshot +#define whal_Stm32wba_AesCtr_Start whal_AesCtr_Start +#define whal_Stm32wba_AesCtr_Process whal_AesCtr_Process #endif #ifdef WHAL_CFG_STM32WBA_AES_GCM_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_GCM_DIRECT_API_MAPPING +#define whal_Stm32wba_AesGcm_Oneshot whal_AesGcm_Oneshot +#define whal_Stm32wba_AesGcm_Start whal_AesGcm_Start +#define whal_Stm32wba_AesGcm_Process whal_AesGcm_Process +#define whal_Stm32wba_AesGcm_Finalize whal_AesGcm_Finalize #endif #ifdef WHAL_CFG_STM32WBA_AES_GMAC_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_GMAC_DIRECT_API_MAPPING +#define whal_Stm32wba_AesGmac_Oneshot whal_AesGmac_Oneshot #endif #ifdef WHAL_CFG_STM32WBA_AES_CCM_DIRECT_API_MAPPING -#define WHAL_CFG_STM32WB_AES_CCM_DIRECT_API_MAPPING +#define whal_Stm32wba_AesCcm_Oneshot whal_AesCcm_Oneshot +#define whal_Stm32wba_AesCcm_Start whal_AesCcm_Start +#define whal_Stm32wba_AesCcm_Process whal_AesCcm_Process +#define whal_Stm32wba_AesCcm_Finalize whal_AesCcm_Finalize #endif -#include "stm32wb_aes.c" + +/* ---- Init / Deinit ---- */ + +whal_Error whal_Stm32wba_Aes_Init(whal_Crypto *dev) +{ + (void)dev; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32wba_Aes_Deinit(whal_Crypto *dev) +{ + (void)dev; + DisableAes((whal_Crypto *)&whal_Stm32wba_Aes_Dev); + ZeroKeyIv(whal_Stm32wba_Aes_Dev.base); + return WHAL_SUCCESS; +} + +const whal_CryptoDriver whal_Stm32wba_Aes_CryptoDriver = { + .Init = whal_Stm32wba_Aes_Init, + .Deinit = whal_Stm32wba_Aes_Deinit, +}; + + +/* ---- AES-ECB ---- */ + +whal_Error whal_Stm32wba_AesEcb_Oneshot(whal_AesEcb *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *in, void *out, size_t sz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesEcb_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + size_t mode; + size_t keySizeBit; + whal_Error err; + + (void)dev; + + if (!key) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + keySizeBit = (keySz == 32) ? 1 : 0; + mode = (dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_KEYPREP; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, mode) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_ECB) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + if (dir == WHAL_CRYPTO_DECRYPT) { + /* Decryption round key preparation; AES disables itself when done */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + whal_Reg_Update(base, AES_CR_REG, AES_CR_MODE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_DECRYPT)); + } + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + err = ProcessBlockCipher(crypto, in, out, sz); +cleanup: + DisableAes(crypto); + ZeroKeyIv(base); + return err; +} + +whal_Error whal_Stm32wba_AesEcb_Start(whal_AesEcb *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesEcb_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + size_t mode; + size_t keySizeBit; + whal_Error err; + + (void)dev; + + if (!key) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + keySizeBit = (keySz == 32) ? 1 : 0; + mode = (dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_KEYPREP; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, mode) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_ECB) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + if (dir == WHAL_CRYPTO_DECRYPT) { + /* Decryption round key preparation; AES disables itself when done */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + whal_Reg_Update(base, AES_CR_REG, AES_CR_MODE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_DECRYPT)); + } + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + return WHAL_SUCCESS; + +cleanup: + DisableAes(crypto); + ZeroKeyIv(base); + return err; +} + +whal_Error whal_Stm32wba_AesEcb_Process(whal_AesEcb *dev, + const void *in, void *out, size_t sz) +{ + (void)dev; + return ProcessBlockCipher(whal_Stm32wba_AesEcb_Dev.crypto, in, out, sz); +} + +const whal_AesEcbDriver whal_Stm32wba_Aes_EcbDriver = { + .Oneshot = whal_Stm32wba_AesEcb_Oneshot, + .Start = whal_Stm32wba_AesEcb_Start, + .Process = whal_Stm32wba_AesEcb_Process, +}; + + +/* ---- AES-CBC ---- */ + +whal_Error whal_Stm32wba_AesCbc_Oneshot(whal_AesCbc *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv, + const void *in, void *out, size_t sz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesCbc_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + size_t mode; + size_t keySizeBit; + whal_Error err; + + (void)dev; + + if (!key || !iv) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + keySizeBit = (keySz == 32) ? 1 : 0; + mode = (dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_KEYPREP; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, mode) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_CBC) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + if (dir == WHAL_CRYPTO_DECRYPT) { + /* Decryption round key preparation; AES disables itself when done */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + whal_Reg_Update(base, AES_CR_REG, AES_CR_MODE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_DECRYPT)); + } + WriteIv(base, iv); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + err = ProcessBlockCipher(crypto, in, out, sz); +cleanup: + DisableAes(crypto); + ZeroKeyIv(base); + return err; +} + +whal_Error whal_Stm32wba_AesCbc_Start(whal_AesCbc *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv) +{ + whal_Crypto *crypto = whal_Stm32wba_AesCbc_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + size_t mode; + size_t keySizeBit; + whal_Error err; + + (void)dev; + + if (!key || !iv) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + keySizeBit = (keySz == 32) ? 1 : 0; + mode = (dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_KEYPREP; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, mode) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_CBC) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + if (dir == WHAL_CRYPTO_DECRYPT) { + /* Decryption round key preparation; AES disables itself when done */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + whal_Reg_Update(base, AES_CR_REG, AES_CR_MODE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_DECRYPT)); + } + WriteIv(base, iv); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + return WHAL_SUCCESS; + +cleanup: + DisableAes(crypto); + ZeroKeyIv(base); + return err; +} + +whal_Error whal_Stm32wba_AesCbc_Process(whal_AesCbc *dev, + const void *in, void *out, size_t sz) +{ + (void)dev; + return ProcessBlockCipher(whal_Stm32wba_AesCbc_Dev.crypto, in, out, sz); +} + +const whal_AesCbcDriver whal_Stm32wba_Aes_CbcDriver = { + .Oneshot = whal_Stm32wba_AesCbc_Oneshot, + .Start = whal_Stm32wba_AesCbc_Start, + .Process = whal_Stm32wba_AesCbc_Process, +}; + + +/* ---- AES-CTR ---- */ + +whal_Error whal_Stm32wba_AesCtr_Oneshot(whal_AesCtr *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv, + const void *in, void *out, size_t sz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesCtr_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + size_t keySizeBit; + whal_Error err; + + (void)dev; + + if (!key || !iv) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + keySizeBit = (keySz == 32) ? 1 : 0; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_CTR) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + WriteIv(base, iv); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + err = ProcessBlockCipher(crypto, in, out, sz); +cleanup: + DisableAes(crypto); + ZeroKeyIv(base); + return err; +} + +whal_Error whal_Stm32wba_AesCtr_Start(whal_AesCtr *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv) +{ + whal_Crypto *crypto = whal_Stm32wba_AesCtr_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + size_t keySizeBit; + whal_Error err; + + (void)dev; + + if (!key || !iv) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + keySizeBit = (keySz == 32) ? 1 : 0; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_CTR) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + WriteIv(base, iv); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + return WHAL_SUCCESS; + +cleanup: + DisableAes(crypto); + ZeroKeyIv(base); + return err; +} + +whal_Error whal_Stm32wba_AesCtr_Process(whal_AesCtr *dev, + const void *in, void *out, size_t sz) +{ + (void)dev; + return ProcessBlockCipher(whal_Stm32wba_AesCtr_Dev.crypto, in, out, sz); +} + +const whal_AesCtrDriver whal_Stm32wba_Aes_CtrDriver = { + .Oneshot = whal_Stm32wba_AesCtr_Oneshot, + .Start = whal_Stm32wba_AesCtr_Start, + .Process = whal_Stm32wba_AesCtr_Process, +}; + + +/* ---- AES-GCM ---- */ + +whal_Error whal_Stm32wba_AesGcm_Oneshot(whal_AesGcm *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv, size_t ivSz, + const void *aad, size_t aadSz, + const void *in, void *out, size_t sz, + void *tag, size_t tagSz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesGcm_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + const uint8_t *ivBytes = (const uint8_t *)iv; + const uint8_t *aadBytes = (const uint8_t *)aad; + size_t keySizeBit; + size_t mode; + size_t i; + uint8_t tagBuf[16]; + whal_Error err; + + (void)dev; + + if (!key || !iv) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + if (ivSz != 12) + return WHAL_ENOTSUP; + + if (sz > 0 && (!in || !out)) + return WHAL_EINVAL; + + if (aadSz > 0 && !aad) + return WHAL_EINVAL; + + if (!tag || tagSz == 0 || tagSz > 16) + return WHAL_EINVAL; + + keySizeBit = (keySz == 32) ? 1 : 0; + + /* Init phase */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk | + AES_CR_GCMPH_Msk | AES_CR_NPBLB_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_GCM) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_INIT)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + + whal_Reg_Write(base, AES_IVR3_REG, whal_LoadBe32(ivBytes)); + whal_Reg_Write(base, AES_IVR2_REG, whal_LoadBe32(ivBytes + 4)); + whal_Reg_Write(base, AES_IVR1_REG, whal_LoadBe32(ivBytes + 8)); + whal_Reg_Write(base, AES_IVR0_REG, 0x00000002); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + /* Header phase (AAD) */ + if (aadSz > 0) { + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_HEADER)); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + for (i = 0; i < aadSz; i += 16) { + const uint8_t *blkAad = aadBytes + i; + size_t remain = aadSz - i; + uint8_t block[16] = {0}; + size_t j; + + if (remain >= 16) { + WriteBlock(base, blkAad); + } else { + for (j = 0; j < remain; j++) + block[j] = blkAad[j]; + WriteBlock(base, block); + } + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + } + } + + /* Payload phase */ + if (sz > 0) { + mode = (dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_DECRYPT; + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + mode) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_PAYLOAD)); + + if (aadSz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + for (i = 0; i < sz; i += 16) { + const uint8_t *inBlk = (const uint8_t *)in + i; + uint8_t *outBlk = (uint8_t *)out + i; + size_t remain = sz - i; + uint8_t block[16] = {0}; + size_t j; + + if (remain >= 16) { + WriteBlock(base, inBlk); + } else { + if (mode == AES_MODE_ENCRYPT) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_NPBLB_Msk, + whal_SetBits(AES_CR_NPBLB_Msk, + AES_CR_NPBLB_Pos, + 16 - remain)); + } + for (j = 0; j < remain; j++) + block[j] = inBlk[j]; + WriteBlock(base, block); + } + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + if (remain >= 16) { + ReadBlock(base, outBlk); + } else { + ReadBlock(base, block); + for (j = 0; j < remain; j++) + outBlk[j] = block[j]; + } + } + } + + /* Final phase (tag) */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_FINAL)); + + if (aadSz == 0 && sz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, (uint32_t)(aadSz * 8)); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, (uint32_t)(sz * 8)); + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + ReadBlock(base, tagBuf); + + for (i = 0; i < tagSz; i++) + ((uint8_t *)tag)[i] = tagBuf[i]; + +cleanup: + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return err; +} + +whal_Error whal_Stm32wba_AesGcm_Start(whal_AesGcm *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv, size_t ivSz, + const void *aad, size_t aadSz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesGcm_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + const uint8_t *ivBytes = (const uint8_t *)iv; + const uint8_t *aadBytes = (const uint8_t *)aad; + size_t keySizeBit; + size_t mode; + size_t i; + whal_Error err; + + (void)dev; + + if (!key || !iv) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + if (ivSz != 12) + return WHAL_ENOTSUP; + + if (aadSz > 0 && !aad) + return WHAL_EINVAL; + + keySizeBit = (keySz == 32) ? 1 : 0; + + /* Init phase */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk | + AES_CR_GCMPH_Msk | AES_CR_NPBLB_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_GCM) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_INIT)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + + whal_Reg_Write(base, AES_IVR3_REG, whal_LoadBe32(ivBytes)); + whal_Reg_Write(base, AES_IVR2_REG, whal_LoadBe32(ivBytes + 4)); + whal_Reg_Write(base, AES_IVR1_REG, whal_LoadBe32(ivBytes + 8)); + whal_Reg_Write(base, AES_IVR0_REG, 0x00000002); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + /* Header phase (AAD) */ + if (aadSz > 0) { + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_HEADER)); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + for (i = 0; i < aadSz; i += 16) { + const uint8_t *blkAad = aadBytes + i; + size_t remain = aadSz - i; + uint8_t block[16] = {0}; + size_t j; + + if (remain >= 16) { + WriteBlock(base, blkAad); + } else { + for (j = 0; j < remain; j++) + block[j] = blkAad[j]; + WriteBlock(base, block); + } + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + } + } + + /* Transition to payload phase */ + mode = (dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_DECRYPT; + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, mode) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_PAYLOAD)); + + if (aadSz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + { + whal_Stm32wba_AesGcm_State *st = + (whal_Stm32wba_AesGcm_State *)whal_Stm32wba_AesGcm_Dev.state; + st->aadSz = aadSz; + st->dataSz = 0; + } + + return WHAL_SUCCESS; + +cleanup: + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return err; +} + +whal_Error whal_Stm32wba_AesGcm_Process(whal_AesGcm *dev, + const void *in, void *out, size_t sz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesGcm_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + whal_Stm32wba_AesGcm_State *st = + (whal_Stm32wba_AesGcm_State *)whal_Stm32wba_AesGcm_Dev.state; + size_t mode; + size_t i; + whal_Error err; + + (void)dev; + + if (sz == 0) + return WHAL_SUCCESS; + + if (!in || !out) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + + mode = whal_GetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + whal_Reg_Read(base, AES_CR_REG)); + + for (i = 0; i < sz; i += 16) { + const uint8_t *inBlk = (const uint8_t *)in + i; + uint8_t *outBlk = (uint8_t *)out + i; + size_t remain = sz - i; + uint8_t block[16] = {0}; + size_t j; + + if (remain >= 16) { + WriteBlock(base, inBlk); + } else { + if (mode == AES_MODE_ENCRYPT) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_NPBLB_Msk, + whal_SetBits(AES_CR_NPBLB_Msk, + AES_CR_NPBLB_Pos, + 16 - remain)); + } + for (j = 0; j < remain; j++) + block[j] = inBlk[j]; + WriteBlock(base, block); + } + + err = WaitForCCF(base, cfg->timeout); + if (err) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return err; + } + + if (remain >= 16) { + ReadBlock(base, outBlk); + } else { + ReadBlock(base, block); + for (j = 0; j < remain; j++) + outBlk[j] = block[j]; + } + } + + st->dataSz += sz; + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32wba_AesGcm_Finalize(whal_AesGcm *dev, + void *tag, size_t tagSz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesGcm_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + whal_Stm32wba_AesGcm_State *st = + (whal_Stm32wba_AesGcm_State *)whal_Stm32wba_AesGcm_Dev.state; + uint8_t tagBuf[16]; + size_t i; + whal_Error err; + + (void)dev; + + if (!tag || tagSz == 0 || tagSz > 16) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + + /* Final phase (tag) */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_FINAL)); + + if (st->aadSz == 0 && st->dataSz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, (uint32_t)(st->aadSz * 8)); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, (uint32_t)(st->dataSz * 8)); + + err = WaitForCCF(base, cfg->timeout); + if (err) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return err; + } + + ReadBlock(base, tagBuf); + + for (i = 0; i < tagSz; i++) + ((uint8_t *)tag)[i] = tagBuf[i]; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_SUCCESS; +} + +const whal_AesGcmDriver whal_Stm32wba_Aes_GcmDriver = { + .Oneshot = whal_Stm32wba_AesGcm_Oneshot, + .Start = whal_Stm32wba_AesGcm_Start, + .Process = whal_Stm32wba_AesGcm_Process, + .Finalize = whal_Stm32wba_AesGcm_Finalize, +}; + + +/* ---- AES-GMAC ---- */ + +whal_Error whal_Stm32wba_AesGmac_Oneshot(whal_AesGmac *dev, + const void *key, size_t keySz, + const void *iv, size_t ivSz, + const void *aad, size_t aadSz, + void *tag, size_t tagSz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesGmac_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + const uint8_t *ivBytes = (const uint8_t *)iv; + const uint8_t *aadBytes = (const uint8_t *)aad; + size_t keySizeBit; + size_t i; + uint8_t tagBuf[16]; + whal_Error err; + + (void)dev; + + if (!key || !iv) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + if (ivSz != 12) + return WHAL_ENOTSUP; + + if (aadSz > 0 && !aad) + return WHAL_EINVAL; + + if (!tag || tagSz == 0 || tagSz > 16) + return WHAL_EINVAL; + + keySizeBit = (keySz == 32) ? 1 : 0; + + /* Init phase */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk | + AES_CR_GCMPH_Msk | AES_CR_NPBLB_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_GCM) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_INIT)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + + whal_Reg_Write(base, AES_IVR3_REG, whal_LoadBe32(ivBytes)); + whal_Reg_Write(base, AES_IVR2_REG, whal_LoadBe32(ivBytes + 4)); + whal_Reg_Write(base, AES_IVR1_REG, whal_LoadBe32(ivBytes + 8)); + whal_Reg_Write(base, AES_IVR0_REG, 0x00000002); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + /* Header phase (AAD) */ + if (aadSz > 0) { + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_HEADER)); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + for (i = 0; i < aadSz; i += 16) { + const uint8_t *blkAad = aadBytes + i; + size_t remain = aadSz - i; + uint8_t block[16] = {0}; + size_t j; + + if (remain >= 16) { + WriteBlock(base, blkAad); + } else { + for (j = 0; j < remain; j++) + block[j] = blkAad[j]; + WriteBlock(base, block); + } + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + } + } + + /* Final phase (tag) -- no payload for GMAC */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_FINAL)); + + if (aadSz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, (uint32_t)(aadSz * 8)); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + ReadBlock(base, tagBuf); + + for (i = 0; i < tagSz; i++) + ((uint8_t *)tag)[i] = tagBuf[i]; + +cleanup: + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return err; +} + +const whal_AesGmacDriver whal_Stm32wba_Aes_GmacDriver = { + .Oneshot = whal_Stm32wba_AesGmac_Oneshot, +}; + + +/* ---- AES-CCM ---- */ + +whal_Error whal_Stm32wba_AesCcm_Oneshot(whal_AesCcm *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *nonce, size_t nonceSz, + const void *aad, size_t aadSz, + const void *in, void *out, size_t sz, + void *tag, size_t tagSz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesCcm_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + const uint8_t *nonceBytes = (const uint8_t *)nonce; + const uint8_t *aadBytes = (const uint8_t *)aad; + size_t keySizeBit; + size_t mode; + size_t i; + uint8_t b0[16]; + uint8_t tagBuf[16]; + whal_Error err; + + (void)dev; + + if (!key || !nonce) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + if (nonceSz < 7 || nonceSz > 13) + return WHAL_EINVAL; + + if (sz > 0 && (!in || !out)) + return WHAL_EINVAL; + + if (aadSz > 0 && !aad) + return WHAL_EINVAL; + + if (!tag || tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0) + return WHAL_EINVAL; + + keySizeBit = (keySz == 32) ? 1 : 0; + + /* Build B0 */ + { + size_t q = 15 - nonceSz; + size_t t = tagSz; + uint8_t flags = (uint8_t)(((aadSz > 0) ? 0x40 : 0) | + (((t - 2) / 2) << 3) | + (q - 1)); + b0[0] = flags; + for (i = 0; i < nonceSz; i++) + b0[1 + i] = nonceBytes[i]; + + { + size_t msgLen = sz; + size_t j; + for (j = 0; j < q; j++) { + b0[15 - j] = (uint8_t)(msgLen & 0xFF); + msgLen >>= 8; + } + } + } + + /* Init phase */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk | + AES_CR_GCMPH_Msk | AES_CR_NPBLB_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, 0) | + AES_CR_CHMOD2_Msk | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_INIT)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + WriteIv(base, b0); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + /* Header phase (AAD) */ + if (aadSz > 0) { + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_HEADER)); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + { + uint8_t hdrBuf[16] = {0}; + size_t hdrOff = 0; + size_t aadOff = 0; + size_t j; + + hdrBuf[0] = (uint8_t)(aadSz >> 8); + hdrBuf[1] = (uint8_t)(aadSz); + hdrOff = 2; + + while (hdrOff < 16 && aadOff < aadSz) { + hdrBuf[hdrOff++] = aadBytes[aadOff++]; + } + + WriteBlock(base, hdrBuf); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + while (aadOff < aadSz) { + uint8_t block[16] = {0}; + + for (j = 0; j < 16 && aadOff < aadSz; j++) + block[j] = aadBytes[aadOff++]; + + WriteBlock(base, block); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + } + } + } + + /* Payload phase */ + if (sz > 0) { + mode = (dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_DECRYPT; + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + mode) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_PAYLOAD)); + + if (aadSz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + for (i = 0; i < sz; i += 16) { + const uint8_t *inBlk = (const uint8_t *)in + i; + uint8_t *outBlk = (uint8_t *)out + i; + size_t remain = sz - i; + uint8_t block[16] = {0}; + size_t j; + + if (remain >= 16) { + WriteBlock(base, inBlk); + } else { + if (mode == AES_MODE_DECRYPT) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_NPBLB_Msk, + whal_SetBits(AES_CR_NPBLB_Msk, + AES_CR_NPBLB_Pos, + 16 - remain)); + } + for (j = 0; j < remain; j++) + block[j] = inBlk[j]; + WriteBlock(base, block); + } + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + if (remain >= 16) { + ReadBlock(base, outBlk); + } else { + ReadBlock(base, block); + for (j = 0; j < remain; j++) + outBlk[j] = block[j]; + } + } + } + + /* Final phase (tag) */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_FINAL)); + + if (aadSz == 0 && sz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + ReadBlock(base, tagBuf); + + for (i = 0; i < tagSz; i++) + ((uint8_t *)tag)[i] = tagBuf[i]; + +cleanup: + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return err; +} + +whal_Error whal_Stm32wba_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *nonce, size_t nonceSz, + const void *aad, size_t aadSz, + size_t tagSz, size_t sz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesCcm_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + const uint8_t *nonceBytes = (const uint8_t *)nonce; + const uint8_t *aadBytes = (const uint8_t *)aad; + size_t keySizeBit; + size_t mode; + size_t i; + uint8_t b0[16]; + whal_Error err; + + (void)dev; + + if (!key || !nonce) + return WHAL_EINVAL; + + if (keySz != 16 && keySz != 32) + return WHAL_ENOTSUP; + + if (nonceSz < 7 || nonceSz > 13) + return WHAL_EINVAL; + + if (aadSz > 0 && !aad) + return WHAL_EINVAL; + + if (tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0) + return WHAL_EINVAL; + + keySizeBit = (keySz == 32) ? 1 : 0; + + /* Build B0 */ + { + size_t q = 15 - nonceSz; + size_t t = tagSz; + uint8_t flags = (uint8_t)(((aadSz > 0) ? 0x40 : 0) | + (((t - 2) / 2) << 3) | + (q - 1)); + b0[0] = flags; + for (i = 0; i < nonceSz; i++) + b0[1 + i] = nonceBytes[i]; + + { + size_t msgLen = sz; + size_t j; + for (j = 0; j < q; j++) { + b0[15 - j] = (uint8_t)(msgLen & 0xFF); + msgLen >>= 8; + } + } + } + + /* Init phase */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk | + AES_CR_GCMPH_Msk | AES_CR_NPBLB_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, 0) | + AES_CR_CHMOD2_Msk | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_INIT)); + + err = LoadKey(base, key, keySz, cfg->timeout); + if (err) + goto cleanup; + WriteIv(base, b0); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + /* Header phase (AAD) */ + if (aadSz > 0) { + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_HEADER)); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + { + uint8_t hdrBuf[16] = {0}; + size_t hdrOff = 0; + size_t aadOff = 0; + size_t j; + + hdrBuf[0] = (uint8_t)(aadSz >> 8); + hdrBuf[1] = (uint8_t)(aadSz); + hdrOff = 2; + + while (hdrOff < 16 && aadOff < aadSz) { + hdrBuf[hdrOff++] = aadBytes[aadOff++]; + } + + WriteBlock(base, hdrBuf); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + + while (aadOff < aadSz) { + uint8_t block[16] = {0}; + + for (j = 0; j < 16 && aadOff < aadSz; j++) + block[j] = aadBytes[aadOff++]; + + WriteBlock(base, block); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; + } + } + } + + /* Transition to payload phase */ + mode = (dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_DECRYPT; + + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, mode) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_PAYLOAD)); + + if (aadSz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + { + whal_Stm32wba_AesCcm_State *st = + (whal_Stm32wba_AesCcm_State *)whal_Stm32wba_AesCcm_Dev.state; + st->aadSz = aadSz; + st->dataSz = 0; + } + + return WHAL_SUCCESS; + +cleanup: + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return err; +} + +whal_Error whal_Stm32wba_AesCcm_Process(whal_AesCcm *dev, + const void *in, void *out, size_t sz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesCcm_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + whal_Stm32wba_AesCcm_State *st = + (whal_Stm32wba_AesCcm_State *)whal_Stm32wba_AesCcm_Dev.state; + size_t mode; + size_t i; + whal_Error err; + + (void)dev; + + if (sz == 0) + return WHAL_SUCCESS; + + if (!in || !out) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + + mode = whal_GetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + whal_Reg_Read(base, AES_CR_REG)); + + for (i = 0; i < sz; i += 16) { + const uint8_t *inBlk = (const uint8_t *)in + i; + uint8_t *outBlk = (uint8_t *)out + i; + size_t remain = sz - i; + uint8_t block[16] = {0}; + size_t j; + + if (remain >= 16) { + WriteBlock(base, inBlk); + } else { + if (mode == AES_MODE_DECRYPT) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_NPBLB_Msk, + whal_SetBits(AES_CR_NPBLB_Msk, + AES_CR_NPBLB_Pos, + 16 - remain)); + } + for (j = 0; j < remain; j++) + block[j] = inBlk[j]; + WriteBlock(base, block); + } + + err = WaitForCCF(base, cfg->timeout); + if (err) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return err; + } + + if (remain >= 16) { + ReadBlock(base, outBlk); + } else { + ReadBlock(base, block); + for (j = 0; j < remain; j++) + outBlk[j] = block[j]; + } + } + + st->dataSz += sz; + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32wba_AesCcm_Finalize(whal_AesCcm *dev, + void *tag, size_t tagSz) +{ + whal_Crypto *crypto = whal_Stm32wba_AesCcm_Dev.crypto; + const whal_Stm32wba_Aes_Cfg *cfg = + (const whal_Stm32wba_Aes_Cfg *)crypto->cfg; + size_t base = crypto->base; + whal_Stm32wba_AesCcm_State *st = + (whal_Stm32wba_AesCcm_State *)whal_Stm32wba_AesCcm_Dev.state; + uint8_t tagBuf[16]; + size_t i; + whal_Error err; + + (void)dev; + + if (!tag || tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + + /* Final phase (tag) */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_FINAL)); + + if (st->aadSz == 0 && st->dataSz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + + err = WaitForCCF(base, cfg->timeout); + if (err) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return err; + } + + ReadBlock(base, tagBuf); + + for (i = 0; i < tagSz; i++) + ((uint8_t *)tag)[i] = tagBuf[i]; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_SUCCESS; +} + +const whal_AesCcmDriver whal_Stm32wba_Aes_CcmDriver = { + .Oneshot = whal_Stm32wba_AesCcm_Oneshot, + .Start = whal_Stm32wba_AesCcm_Start, + .Process = whal_Stm32wba_AesCcm_Process, + .Finalize = whal_Stm32wba_AesCcm_Finalize, +}; diff --git a/wolfHAL/crypto/stm32u5_aes.h b/wolfHAL/crypto/stm32u5_aes.h index 0cdb736..97706b4 100644 --- a/wolfHAL/crypto/stm32u5_aes.h +++ b/wolfHAL/crypto/stm32u5_aes.h @@ -24,45 +24,45 @@ /** * @file stm32u5_aes.h - * @brief STM32U5 AES driver (alias for STM32WB AES). + * @brief STM32U5 AES driver (alias for STM32WBA AES). * - * The STM32U5 AES peripheral is register-compatible with the STM32WB AES. - * This header re-exports the STM32WB AES driver types and symbols under + * The STM32U5 AES peripheral is register-compatible with the STM32WBA AES. + * This header re-exports the STM32WBA AES driver types and symbols under * STM32U5-specific names. */ -#include +#include -typedef whal_Stm32wb_Aes_Cfg whal_Stm32u5_Aes_Cfg; +typedef whal_Stm32wba_Aes_Cfg whal_Stm32u5_Aes_Cfg; -typedef whal_Stm32wb_AesGcm_State whal_Stm32u5_AesGcm_State; -typedef whal_Stm32wb_AesCcm_State whal_Stm32u5_AesCcm_State; +typedef whal_Stm32wba_AesGcm_State whal_Stm32u5_AesGcm_State; +typedef whal_Stm32wba_AesCcm_State whal_Stm32u5_AesCcm_State; -#define whal_Stm32u5_Aes_Dev whal_Stm32wb_Aes_Dev -#define whal_Stm32u5_AesEcb_Dev whal_Stm32wb_AesEcb_Dev -#define whal_Stm32u5_AesCbc_Dev whal_Stm32wb_AesCbc_Dev -#define whal_Stm32u5_AesCtr_Dev whal_Stm32wb_AesCtr_Dev -#define whal_Stm32u5_AesGcm_Dev whal_Stm32wb_AesGcm_Dev -#define whal_Stm32u5_AesGmac_Dev whal_Stm32wb_AesGmac_Dev -#define whal_Stm32u5_AesCcm_Dev whal_Stm32wb_AesCcm_Dev +#define whal_Stm32u5_Aes_Dev whal_Stm32wba_Aes_Dev +#define whal_Stm32u5_AesEcb_Dev whal_Stm32wba_AesEcb_Dev +#define whal_Stm32u5_AesCbc_Dev whal_Stm32wba_AesCbc_Dev +#define whal_Stm32u5_AesCtr_Dev whal_Stm32wba_AesCtr_Dev +#define whal_Stm32u5_AesGcm_Dev whal_Stm32wba_AesGcm_Dev +#define whal_Stm32u5_AesGmac_Dev whal_Stm32wba_AesGmac_Dev +#define whal_Stm32u5_AesCcm_Dev whal_Stm32wba_AesCcm_Dev -#define whal_Stm32u5_Aes_CryptoDriver whal_Stm32wb_Aes_CryptoDriver +#define whal_Stm32u5_Aes_CryptoDriver whal_Stm32wba_Aes_CryptoDriver -#define whal_Stm32u5_Aes_EcbDriver whal_Stm32wb_Aes_EcbDriver -#define whal_Stm32u5_Aes_CbcDriver whal_Stm32wb_Aes_CbcDriver -#define whal_Stm32u5_Aes_CtrDriver whal_Stm32wb_Aes_CtrDriver -#define whal_Stm32u5_Aes_GcmDriver whal_Stm32wb_Aes_GcmDriver -#define whal_Stm32u5_Aes_GmacDriver whal_Stm32wb_Aes_GmacDriver -#define whal_Stm32u5_Aes_CcmDriver whal_Stm32wb_Aes_CcmDriver +#define whal_Stm32u5_Aes_EcbDriver whal_Stm32wba_Aes_EcbDriver +#define whal_Stm32u5_Aes_CbcDriver whal_Stm32wba_Aes_CbcDriver +#define whal_Stm32u5_Aes_CtrDriver whal_Stm32wba_Aes_CtrDriver +#define whal_Stm32u5_Aes_GcmDriver whal_Stm32wba_Aes_GcmDriver +#define whal_Stm32u5_Aes_GmacDriver whal_Stm32wba_Aes_GmacDriver +#define whal_Stm32u5_Aes_CcmDriver whal_Stm32wba_Aes_CcmDriver /* Config initializer macro aliases. The U5 wolfHAL_board.h supplies the bodies - * under U5-prefixed names; the WB driver source consumes the WB names. */ -#define WHAL_CFG_STM32WB_AES_DEV WHAL_CFG_STM32U5_AES_DEV -#define WHAL_CFG_STM32WB_AES_ECB_DEV WHAL_CFG_STM32U5_AES_ECB_DEV -#define WHAL_CFG_STM32WB_AES_CBC_DEV WHAL_CFG_STM32U5_AES_CBC_DEV -#define WHAL_CFG_STM32WB_AES_CTR_DEV WHAL_CFG_STM32U5_AES_CTR_DEV -#define WHAL_CFG_STM32WB_AES_GCM_DEV WHAL_CFG_STM32U5_AES_GCM_DEV -#define WHAL_CFG_STM32WB_AES_GMAC_DEV WHAL_CFG_STM32U5_AES_GMAC_DEV -#define WHAL_CFG_STM32WB_AES_CCM_DEV WHAL_CFG_STM32U5_AES_CCM_DEV + * under U5-prefixed names; the WBA driver source consumes the WBA names. */ +#define WHAL_CFG_STM32WBA_AES_DEV WHAL_CFG_STM32U5_AES_DEV +#define WHAL_CFG_STM32WBA_AES_ECB_DEV WHAL_CFG_STM32U5_AES_ECB_DEV +#define WHAL_CFG_STM32WBA_AES_CBC_DEV WHAL_CFG_STM32U5_AES_CBC_DEV +#define WHAL_CFG_STM32WBA_AES_CTR_DEV WHAL_CFG_STM32U5_AES_CTR_DEV +#define WHAL_CFG_STM32WBA_AES_GCM_DEV WHAL_CFG_STM32U5_AES_GCM_DEV +#define WHAL_CFG_STM32WBA_AES_GMAC_DEV WHAL_CFG_STM32U5_AES_GMAC_DEV +#define WHAL_CFG_STM32WBA_AES_CCM_DEV WHAL_CFG_STM32U5_AES_CCM_DEV #endif /* WHAL_STM32U5_AES_H */ diff --git a/wolfHAL/crypto/stm32wba_aes.h b/wolfHAL/crypto/stm32wba_aes.h index bba18f8..3f6a77d 100644 --- a/wolfHAL/crypto/stm32wba_aes.h +++ b/wolfHAL/crypto/stm32wba_aes.h @@ -22,47 +22,415 @@ #ifndef WHAL_STM32WBA_AES_H #define WHAL_STM32WBA_AES_H +#include +#include + /** * @file stm32wba_aes.h - * @brief STM32WBA AES driver (alias for STM32WB AES). - * - * The STM32WBA AES peripheral is register-compatible with the STM32WB AES. - * This header re-exports the STM32WB AES driver types and symbols under - * STM32WBA-specific names. - */ - -#include - -typedef whal_Stm32wb_Aes_Cfg whal_Stm32wba_Aes_Cfg; - -typedef whal_Stm32wb_AesGcm_State whal_Stm32wba_AesGcm_State; -typedef whal_Stm32wb_AesCcm_State whal_Stm32wba_AesCcm_State; - -#define whal_Stm32wba_Aes_Dev whal_Stm32wb_Aes_Dev -#define whal_Stm32wba_AesEcb_Dev whal_Stm32wb_AesEcb_Dev -#define whal_Stm32wba_AesCbc_Dev whal_Stm32wb_AesCbc_Dev -#define whal_Stm32wba_AesCtr_Dev whal_Stm32wb_AesCtr_Dev -#define whal_Stm32wba_AesGcm_Dev whal_Stm32wb_AesGcm_Dev -#define whal_Stm32wba_AesGmac_Dev whal_Stm32wb_AesGmac_Dev -#define whal_Stm32wba_AesCcm_Dev whal_Stm32wb_AesCcm_Dev - -#define whal_Stm32wba_Aes_CryptoDriver whal_Stm32wb_Aes_CryptoDriver - -#define whal_Stm32wba_Aes_EcbDriver whal_Stm32wb_Aes_EcbDriver -#define whal_Stm32wba_Aes_CbcDriver whal_Stm32wb_Aes_CbcDriver -#define whal_Stm32wba_Aes_CtrDriver whal_Stm32wb_Aes_CtrDriver -#define whal_Stm32wba_Aes_GcmDriver whal_Stm32wb_Aes_GcmDriver -#define whal_Stm32wba_Aes_GmacDriver whal_Stm32wb_Aes_GmacDriver -#define whal_Stm32wba_Aes_CcmDriver whal_Stm32wb_Aes_CcmDriver - -/* Config initializer macro aliases. The WBA wolfHAL_board.h supplies the bodies - * under WBA-prefixed names; the WB driver source consumes the WB names. */ -#define WHAL_CFG_STM32WB_AES_DEV WHAL_CFG_STM32WBA_AES_DEV -#define WHAL_CFG_STM32WB_AES_ECB_DEV WHAL_CFG_STM32WBA_AES_ECB_DEV -#define WHAL_CFG_STM32WB_AES_CBC_DEV WHAL_CFG_STM32WBA_AES_CBC_DEV -#define WHAL_CFG_STM32WB_AES_CTR_DEV WHAL_CFG_STM32WBA_AES_CTR_DEV -#define WHAL_CFG_STM32WB_AES_GCM_DEV WHAL_CFG_STM32WBA_AES_GCM_DEV -#define WHAL_CFG_STM32WB_AES_GMAC_DEV WHAL_CFG_STM32WBA_AES_GMAC_DEV -#define WHAL_CFG_STM32WB_AES_CCM_DEV WHAL_CFG_STM32WBA_AES_CCM_DEV + * @brief STM32WBA AES hardware accelerator driver. + * + * The STM32WBA AES peripheral supports 128/256-bit keys in ECB, CBC, + * CTR, GCM, GMAC, and CCM modes. Each algorithm is exposed through + * a per-algorithm vtable with Oneshot/Start/Process/Finalize operations. + */ + +/** + * @brief AES device configuration. + */ +typedef struct { + whal_Timeout *timeout; +} whal_Stm32wba_Aes_Cfg; + +/* ---- Streaming state ---- */ + +/** + * @brief AES-GCM streaming state (aadSz/dataSz for final-phase GHASH). + */ +typedef struct { + size_t aadSz; + size_t dataSz; +} whal_Stm32wba_AesGcm_State; + +/** + * @brief AES-CCM streaming state (aadSz/dataSz for final-phase tag). + */ +typedef struct { + size_t aadSz; + size_t dataSz; +} whal_Stm32wba_AesCcm_State; + +/* ---- Direct API mapping ---- */ + +#ifdef WHAL_CFG_STM32WBA_AES_INIT_DIRECT_API_MAPPING +#define whal_Stm32wba_Aes_Init whal_Crypto_Init +#define whal_Stm32wba_Aes_Deinit whal_Crypto_Deinit +#endif + +#ifdef WHAL_CFG_STM32WBA_AES_ECB_DIRECT_API_MAPPING +#define whal_Stm32wba_AesEcb_Oneshot whal_AesEcb_Oneshot +#define whal_Stm32wba_AesEcb_Start whal_AesEcb_Start +#define whal_Stm32wba_AesEcb_Process whal_AesEcb_Process +#endif + +#ifdef WHAL_CFG_STM32WBA_AES_CBC_DIRECT_API_MAPPING +#define whal_Stm32wba_AesCbc_Oneshot whal_AesCbc_Oneshot +#define whal_Stm32wba_AesCbc_Start whal_AesCbc_Start +#define whal_Stm32wba_AesCbc_Process whal_AesCbc_Process +#endif + +#ifdef WHAL_CFG_STM32WBA_AES_CTR_DIRECT_API_MAPPING +#define whal_Stm32wba_AesCtr_Oneshot whal_AesCtr_Oneshot +#define whal_Stm32wba_AesCtr_Start whal_AesCtr_Start +#define whal_Stm32wba_AesCtr_Process whal_AesCtr_Process +#endif + +#ifdef WHAL_CFG_STM32WBA_AES_GCM_DIRECT_API_MAPPING +#define whal_Stm32wba_AesGcm_Oneshot whal_AesGcm_Oneshot +#define whal_Stm32wba_AesGcm_Start whal_AesGcm_Start +#define whal_Stm32wba_AesGcm_Process whal_AesGcm_Process +#define whal_Stm32wba_AesGcm_Finalize whal_AesGcm_Finalize +#endif + +#ifdef WHAL_CFG_STM32WBA_AES_GMAC_DIRECT_API_MAPPING +#define whal_Stm32wba_AesGmac_Oneshot whal_AesGmac_Oneshot +#endif + +#ifdef WHAL_CFG_STM32WBA_AES_CCM_DIRECT_API_MAPPING +#define whal_Stm32wba_AesCcm_Oneshot whal_AesCcm_Oneshot +#define whal_Stm32wba_AesCcm_Start whal_AesCcm_Start +#define whal_Stm32wba_AesCcm_Process whal_AesCcm_Process +#define whal_Stm32wba_AesCcm_Finalize whal_AesCcm_Finalize +#endif + +/* ---- Init / Deinit ---- */ + +/** + * @brief Initialize the STM32WBA AES peripheral. + * + * @param dev Crypto device instance. + */ +whal_Error whal_Stm32wba_Aes_Init(whal_Crypto *dev); + +/** + * @brief Deinitialize the STM32WBA AES peripheral. + * + * @param dev Crypto device instance. + */ +whal_Error whal_Stm32wba_Aes_Deinit(whal_Crypto *dev); + +/* ---- AES-ECB ---- */ + +/** + * @brief AES-ECB one-shot encrypt or decrypt. + * + * @param dev AES-ECB device instance. + * @param dir Encrypt or decrypt. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + * @param in Input data (multiple of 16 bytes). + * @param out Output buffer. + * @param sz Data size in bytes. + */ +whal_Error whal_Stm32wba_AesEcb_Oneshot(whal_AesEcb *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *in, void *out, size_t sz); + +/** + * @brief Start an AES-ECB streaming session (load key). + * + * @param dev AES-ECB device instance. + * @param dir Encrypt or decrypt. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + */ +whal_Error whal_Stm32wba_AesEcb_Start(whal_AesEcb *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz); + +/** + * @brief Process data through an active AES-ECB session. + * + * @param dev AES-ECB device instance. + * @param in Input data (multiple of 16 bytes). + * @param out Output buffer. + * @param sz Data size in bytes. + */ +whal_Error whal_Stm32wba_AesEcb_Process(whal_AesEcb *dev, + const void *in, void *out, size_t sz); + +/* ---- AES-CBC ---- */ + +/** + * @brief AES-CBC one-shot encrypt or decrypt. + * + * @param dev AES-CBC device instance. + * @param dir Encrypt or decrypt. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + * @param iv Initialization vector (16 bytes). + * @param in Input data (multiple of 16 bytes). + * @param out Output buffer. + * @param sz Data size in bytes. + */ +whal_Error whal_Stm32wba_AesCbc_Oneshot(whal_AesCbc *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv, + const void *in, void *out, size_t sz); + +/** + * @brief Start an AES-CBC streaming session (load key and IV). + * + * @param dev AES-CBC device instance. + * @param dir Encrypt or decrypt. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + * @param iv Initialization vector (16 bytes). + */ +whal_Error whal_Stm32wba_AesCbc_Start(whal_AesCbc *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv); + +/** + * @brief Process data through an active AES-CBC session. + * + * @param dev AES-CBC device instance. + * @param in Input data (multiple of 16 bytes). + * @param out Output buffer. + * @param sz Data size in bytes. + */ +whal_Error whal_Stm32wba_AesCbc_Process(whal_AesCbc *dev, + const void *in, void *out, size_t sz); + +/* ---- AES-CTR ---- */ + +/** + * @brief AES-CTR one-shot encrypt or decrypt. + * + * @param dev AES-CTR device instance. + * @param dir Encrypt or decrypt. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + * @param iv Initial counter block (16 bytes). + * @param in Input data. + * @param out Output buffer. + * @param sz Data size in bytes. + */ +whal_Error whal_Stm32wba_AesCtr_Oneshot(whal_AesCtr *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv, + const void *in, void *out, size_t sz); + +/** + * @brief Start an AES-CTR streaming session (load key and counter). + * + * @param dev AES-CTR device instance. + * @param dir Encrypt or decrypt. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + * @param iv Initial counter block (16 bytes). + */ +whal_Error whal_Stm32wba_AesCtr_Start(whal_AesCtr *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv); + +/** + * @brief Process data through an active AES-CTR session. + * + * @param dev AES-CTR device instance. + * @param in Input data. + * @param out Output buffer. + * @param sz Data size in bytes. + */ +whal_Error whal_Stm32wba_AesCtr_Process(whal_AesCtr *dev, + const void *in, void *out, size_t sz); + +/* ---- AES-GCM ---- */ + +/** + * @brief AES-GCM one-shot authenticated encrypt or decrypt. + * + * @param dev AES-GCM device instance. + * @param dir Encrypt or decrypt. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + * @param iv Initialization vector. + * @param ivSz IV size in bytes (typically 12). + * @param aad Additional authenticated data. + * @param aadSz AAD size in bytes. + * @param in Input data. + * @param out Output buffer. + * @param sz Data size in bytes. + * @param tag Authentication tag output. + * @param tagSz Tag size in bytes (up to 16). + */ +whal_Error whal_Stm32wba_AesGcm_Oneshot(whal_AesGcm *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv, size_t ivSz, + const void *aad, size_t aadSz, + const void *in, void *out, size_t sz, + void *tag, size_t tagSz); + +/** + * @brief Start an AES-GCM streaming session (init + header phases). + * + * @param dev AES-GCM device instance. + * @param dir Encrypt or decrypt. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + * @param iv Initialization vector. + * @param ivSz IV size in bytes (typically 12). + * @param aad Additional authenticated data. + * @param aadSz AAD size in bytes. + */ +whal_Error whal_Stm32wba_AesGcm_Start(whal_AesGcm *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *iv, size_t ivSz, + const void *aad, size_t aadSz); + +/** + * @brief Process payload data through an active AES-GCM session. + * + * @param dev AES-GCM device instance. + * @param in Input data. + * @param out Output buffer. + * @param sz Data size in bytes. + */ +whal_Error whal_Stm32wba_AesGcm_Process(whal_AesGcm *dev, + const void *in, void *out, size_t sz); + +/** + * @brief Finalize an AES-GCM session and produce the authentication tag. + * + * @param dev AES-GCM device instance. + * @param tag Authentication tag output. + * @param tagSz Tag size in bytes (up to 16). + */ +whal_Error whal_Stm32wba_AesGcm_Finalize(whal_AesGcm *dev, + void *tag, size_t tagSz); + +/* ---- AES-GMAC ---- */ + +/** + * @brief AES-GMAC one-shot authentication (no payload). + * + * @param dev AES-GMAC device instance. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + * @param iv Initialization vector. + * @param ivSz IV size in bytes (typically 12). + * @param aad Authenticated data. + * @param aadSz Data size in bytes. + * @param tag Authentication tag output. + * @param tagSz Tag size in bytes (up to 16). + */ +whal_Error whal_Stm32wba_AesGmac_Oneshot(whal_AesGmac *dev, + const void *key, size_t keySz, + const void *iv, size_t ivSz, + const void *aad, size_t aadSz, + void *tag, size_t tagSz); + +/* ---- AES-CCM ---- */ + +/** + * @brief AES-CCM one-shot authenticated encrypt or decrypt. + * + * @param dev AES-CCM device instance. + * @param dir Encrypt or decrypt. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + * @param nonce Nonce buffer. + * @param nonceSz Nonce size in bytes (7-13). + * @param aad Additional authenticated data. + * @param aadSz AAD size in bytes. + * @param in Input data. + * @param out Output buffer. + * @param sz Data size in bytes. + * @param tag Authentication tag output. + * @param tagSz Tag size in bytes (4, 6, 8, 10, 12, 14, or 16). + */ +whal_Error whal_Stm32wba_AesCcm_Oneshot(whal_AesCcm *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *nonce, size_t nonceSz, + const void *aad, size_t aadSz, + const void *in, void *out, size_t sz, + void *tag, size_t tagSz); + +/** + * @brief Start an AES-CCM streaming session (init + header phases). + * + * @param dev AES-CCM device instance. + * @param dir Encrypt or decrypt. + * @param key Key buffer. + * @param keySz Key size in bytes (16 or 32). + * @param nonce Nonce buffer. + * @param nonceSz Nonce size in bytes (7-13). + * @param aad Additional authenticated data. + * @param aadSz AAD size in bytes. + * @param tagSz Tag size (needed for B0 block construction). + * @param sz Total payload size (needed for B0 block construction). + */ +whal_Error whal_Stm32wba_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, + const void *key, size_t keySz, + const void *nonce, size_t nonceSz, + const void *aad, size_t aadSz, + size_t tagSz, size_t sz); + +/** + * @brief Process payload data through an active AES-CCM session. + * + * @param dev AES-CCM device instance. + * @param in Input data. + * @param out Output buffer. + * @param sz Data size in bytes. + */ +whal_Error whal_Stm32wba_AesCcm_Process(whal_AesCcm *dev, + const void *in, void *out, size_t sz); + +/** + * @brief Finalize an AES-CCM session and produce the authentication tag. + * + * @param dev AES-CCM device instance. + * @param tag Authentication tag output. + * @param tagSz Tag size in bytes. + */ +whal_Error whal_Stm32wba_AesCcm_Finalize(whal_AesCcm *dev, + void *tag, size_t tagSz); + +/* ---- Singleton externs ---- */ + +/* + * @brief Platform-owned AES + mode singletons. Defined in the driver TU + * from the WHAL_CFG_STM32WBA_AES*_DEV initializers in wolfHAL_board.h. + */ +extern const whal_Crypto whal_Stm32wba_Aes_Dev; +extern const whal_AesEcb whal_Stm32wba_AesEcb_Dev; +extern const whal_AesCbc whal_Stm32wba_AesCbc_Dev; +extern const whal_AesCtr whal_Stm32wba_AesCtr_Dev; +extern const whal_AesGcm whal_Stm32wba_AesGcm_Dev; +extern const whal_AesGmac whal_Stm32wba_AesGmac_Dev; +extern const whal_AesCcm whal_Stm32wba_AesCcm_Dev; + +/* ---- Vtable externs ---- */ + +#ifndef WHAL_CFG_STM32WBA_AES_INIT_DIRECT_API_MAPPING +extern const whal_CryptoDriver whal_Stm32wba_Aes_CryptoDriver; +#endif +#ifndef WHAL_CFG_STM32WBA_AES_ECB_DIRECT_API_MAPPING +extern const whal_AesEcbDriver whal_Stm32wba_Aes_EcbDriver; +#endif +#ifndef WHAL_CFG_STM32WBA_AES_CBC_DIRECT_API_MAPPING +extern const whal_AesCbcDriver whal_Stm32wba_Aes_CbcDriver; +#endif +#ifndef WHAL_CFG_STM32WBA_AES_CTR_DIRECT_API_MAPPING +extern const whal_AesCtrDriver whal_Stm32wba_Aes_CtrDriver; +#endif +#ifndef WHAL_CFG_STM32WBA_AES_GCM_DIRECT_API_MAPPING +extern const whal_AesGcmDriver whal_Stm32wba_Aes_GcmDriver; +#endif +#ifndef WHAL_CFG_STM32WBA_AES_GMAC_DIRECT_API_MAPPING +extern const whal_AesGmacDriver whal_Stm32wba_Aes_GmacDriver; +#endif +#ifndef WHAL_CFG_STM32WBA_AES_CCM_DIRECT_API_MAPPING +extern const whal_AesCcmDriver whal_Stm32wba_Aes_CcmDriver; +#endif #endif /* WHAL_STM32WBA_AES_H */ From 853473bc41ac2c9f4b366157e469eb692afd8c06 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Mon, 5 Oct 2026 15:21:26 -0400 Subject: [PATCH 02/18] [stm32wb_pka] Abort the PKA on timeout before wiping operands - Clear EN, clear flags and re-enable on WaitForProcEnd timeout so ZeroOperand is not ignored and no stale PROCENDF/RAMERRF remains - Fix ZeroOperand comment and result-size docs ("exactly", not "at least") --- src/crypto/stm32wb_pka.c | 13 +++++++++---- wolfHAL/crypto/pka.h | 4 ++-- wolfHAL/crypto/stm32wb_pka.h | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/crypto/stm32wb_pka.c b/src/crypto/stm32wb_pka.c index afa93b3..c15f5ee 100644 --- a/src/crypto/stm32wb_pka.c +++ b/src/crypto/stm32wb_pka.c @@ -199,9 +199,9 @@ static void ReadOperand(size_t base, size_t offset, } /* Zero the slot footprint of a prior WriteOperand/ReadOperand call: the - * numWords data words plus the one trailing word. Called on every op's - * success path so the PKA RAM never carries stale operand or result bytes - * into the next operation. */ + * numWords data words plus the one trailing word. Called after every op, + * whatever its result, so the PKA RAM never carries stale operand or result + * bytes into the next operation. */ static void ZeroOperand(size_t base, size_t offset, size_t dataSz) { size_t numWords = (dataSz + 3) / 4; @@ -227,8 +227,13 @@ static whal_Error WaitForProcEnd(size_t base, whal_Timeout *timeout) whal_Reg_Write(base, PKA_CLRFR_REG, clrFlags); return (sr & errFlags) ? WHAL_EHARDWARE : WHAL_SUCCESS; } - if (WHAL_TIMEOUT_EXPIRED(timeout)) + if (WHAL_TIMEOUT_EXPIRED(timeout)) { + /* Abort the operation so the PKA RAM is writable again */ + whal_Reg_Update(base, PKA_CR_REG, PKA_CR_EN_Msk, 0); + whal_Reg_Write(base, PKA_CLRFR_REG, clrFlags); + whal_Reg_Update(base, PKA_CR_REG, PKA_CR_EN_Msk, PKA_CR_EN_Msk); return WHAL_ETIMEOUT; + } } } diff --git a/wolfHAL/crypto/pka.h b/wolfHAL/crypto/pka.h index 82586d3..5426069 100644 --- a/wolfHAL/crypto/pka.h +++ b/wolfHAL/crypto/pka.h @@ -48,7 +48,7 @@ * @param eSz Size of e in bytes. * @param N Modulus, big-endian (odd). * @param NSz Size of N in bytes. - * @param result Output buffer (must be at least NSz bytes). + * @param result Output buffer (must be exactly NSz bytes). * @param resultSz Output size in bytes. * * @retval WHAL_SUCCESS Result written to @p result. @@ -158,7 +158,7 @@ whal_Error whal_Pka_IntSub(const uint8_t *A, size_t ASz, * @param pSz Size of p in bytes. * @param q Prime q, big-endian. * @param qSz Size of q in bytes. - * @param result Output buffer (must be at least pSz + qSz bytes). + * @param result Output buffer (must be exactly pSz + qSz bytes). * @param resultSz Output size in bytes. * * @retval WHAL_SUCCESS Result written to @p result. diff --git a/wolfHAL/crypto/stm32wb_pka.h b/wolfHAL/crypto/stm32wb_pka.h index 2534bf3..f532eab 100644 --- a/wolfHAL/crypto/stm32wb_pka.h +++ b/wolfHAL/crypto/stm32wb_pka.h @@ -85,7 +85,7 @@ whal_Error whal_Stm32wb_Pka_Deinit(whal_Crypto *dev); * @param eSz Size of e in bytes. * @param N Modulus, big-endian (odd). * @param NSz Size of N in bytes. - * @param result Output buffer (must be at least NSz bytes). + * @param result Output buffer (must be exactly NSz bytes). * @param resultSz Output size in bytes. * * @retval WHAL_SUCCESS Result written to @p result. @@ -195,7 +195,7 @@ whal_Error whal_Stm32wb_Pka_IntSub(const uint8_t *A, size_t ASz, * @param pSz Size of p in bytes. * @param q Prime q, big-endian. * @param qSz Size of q in bytes. - * @param result Output buffer (must be at least pSz + qSz bytes). + * @param result Output buffer (must be exactly pSz + qSz bytes). * @param resultSz Output size in bytes. * * @retval WHAL_SUCCESS Result written to @p result. From 6a56a5d1c283c0b402d7d97a0e4270be8fc138f1 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 11:25:38 -0400 Subject: [PATCH 03/18] [flash, test] Guard flash unlock, check status errors, test write-while-locked - Skip the key sequence when already unlocked and return EHARDWARE if LOCK stays set (WB, WBA, U5, H5, F4, F0/F3, C0) - Check FLASH_SR errors after program/erase on WB, F0/F3, C0 - Clear PER on the WB erase error path - Poll WDW before BSY on WBA; bound the L1 SetLatency polls - Document Lock/Unlock as device-wide - Add a WB test that writing while locked fails and leaves flash unchanged --- src/flash/stm32c0_flash.c | 23 +++++++++++-- src/flash/stm32f0_flash.c | 27 ++++++++++++--- src/flash/stm32f4_flash.c | 9 +++-- src/flash/stm32h5_flash.c | 9 +++-- src/flash/stm32l1_flash.c | 24 +++++++------ src/flash/stm32u5_flash.c | 9 +++-- src/flash/stm32wb_flash.c | 31 ++++++++++++----- src/flash/stm32wba_flash.c | 9 +++++ tests/flash/test_stm32wb_flash.c | 58 ++++++++++++++++++++++++++++++++ wolfHAL/flash/flash.h | 16 +++++---- wolfHAL/flash/stm32c0_flash.h | 5 +-- wolfHAL/flash/stm32f0_flash.h | 2 +- wolfHAL/flash/stm32f4_flash.h | 5 +-- wolfHAL/flash/stm32h5_flash.h | 5 +-- wolfHAL/flash/stm32l1_flash.h | 3 +- wolfHAL/flash/stm32wb_flash.h | 17 +++++----- 16 files changed, 199 insertions(+), 53 deletions(-) diff --git a/src/flash/stm32c0_flash.c b/src/flash/stm32c0_flash.c index ed208b1..5ac0f61 100644 --- a/src/flash/stm32c0_flash.c +++ b/src/flash/stm32c0_flash.c @@ -159,8 +159,13 @@ whal_Error whal_Stm32c0_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t l * Unlock sequence: write KEY1 then KEY2 to KEYR register. * Incorrect sequence or order will trigger a bus error. */ - whal_Reg_Update(base, FLASH_KEYR_REG, FLASH_KEYR_KEY_Msk, 0x45670123); - whal_Reg_Update(base, FLASH_KEYR_REG, FLASH_KEYR_KEY_Msk, 0xCDEF89AB); + if (whal_Reg_Read(base, FLASH_CR_REG) & FLASH_CR_LOCK_Msk) { + whal_Reg_Update(base, FLASH_KEYR_REG, FLASH_KEYR_KEY_Msk, 0x45670123); + whal_Reg_Update(base, FLASH_KEYR_REG, FLASH_KEYR_KEY_Msk, 0xCDEF89AB); + } + + if (whal_Reg_Read(base, FLASH_CR_REG) & FLASH_CR_LOCK_Msk) + return WHAL_EHARDWARE; return WHAL_SUCCESS; } @@ -245,6 +250,13 @@ static whal_Error whal_Stm32c0_Flash_WriteOrErase(whal_Flash *flashDev, size_t a FLASH_SR_CFGBSY_Msk, 0, cfg->timeout); if (err) goto cleanup; + + /* Check for errors */ + if (whal_Reg_Read(base, FLASH_SR_REG) & FLASH_SR_ALL_ERR) { + whal_Reg_Update(base, FLASH_SR_REG, FLASH_SR_ALL_ERR, FLASH_SR_ALL_ERR); + err = WHAL_EHARDWARE; + goto cleanup; + } } } else { @@ -272,6 +284,13 @@ static whal_Error whal_Stm32c0_Flash_WriteOrErase(whal_Flash *flashDev, size_t a FLASH_SR_CFGBSY_Msk, 0, cfg->timeout); if (err) goto cleanup; + + /* Check for errors */ + if (whal_Reg_Read(base, FLASH_SR_REG) & FLASH_SR_ALL_ERR) { + whal_Reg_Update(base, FLASH_SR_REG, FLASH_SR_ALL_ERR, FLASH_SR_ALL_ERR); + err = WHAL_EHARDWARE; + goto cleanup; + } } /* Disable page erase mode */ diff --git a/src/flash/stm32f0_flash.c b/src/flash/stm32f0_flash.c index 191b102..9587d14 100644 --- a/src/flash/stm32f0_flash.c +++ b/src/flash/stm32f0_flash.c @@ -103,10 +103,15 @@ whal_Error whal_Stm32f0_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t l (void)addr; (void)len; - whal_Reg_Update(base, FLASH_KEYR_REG, - FLASH_KEYR_KEY_Msk, 0x45670123); - whal_Reg_Update(base, FLASH_KEYR_REG, - FLASH_KEYR_KEY_Msk, 0xCDEF89AB); + if (whal_Reg_Read(base, FLASH_CR_REG) & FLASH_CR_LOCK_Msk) { + whal_Reg_Update(base, FLASH_KEYR_REG, + FLASH_KEYR_KEY_Msk, 0x45670123); + whal_Reg_Update(base, FLASH_KEYR_REG, + FLASH_KEYR_KEY_Msk, 0xCDEF89AB); + } + + if (whal_Reg_Read(base, FLASH_CR_REG) & FLASH_CR_LOCK_Msk) + return WHAL_EHARDWARE; return WHAL_SUCCESS; } @@ -182,6 +187,13 @@ static whal_Error whal_Stm32f0_Flash_WriteOrErase(whal_Flash *flashDev, FLASH_SR_BSY_Msk, 0, cfg->timeout); if (err) goto cleanup; + + /* Check for errors */ + if (whal_Reg_Read(base, FLASH_SR_REG) & FLASH_SR_ALL_ERR) { + whal_Reg_Update(base, FLASH_SR_REG, FLASH_SR_ALL_ERR, FLASH_SR_ALL_ERR); + err = WHAL_EHARDWARE; + goto cleanup; + } } } else { /* Calculate page range (2 KB per page) */ @@ -205,6 +217,13 @@ static whal_Error whal_Stm32f0_Flash_WriteOrErase(whal_Flash *flashDev, FLASH_SR_BSY_Msk, 0, cfg->timeout); if (err) goto cleanup; + + /* Check for errors */ + if (whal_Reg_Read(base, FLASH_SR_REG) & FLASH_SR_ALL_ERR) { + whal_Reg_Update(base, FLASH_SR_REG, FLASH_SR_ALL_ERR, FLASH_SR_ALL_ERR); + err = WHAL_EHARDWARE; + goto cleanup; + } } /* Disable page erase */ diff --git a/src/flash/stm32f4_flash.c b/src/flash/stm32f4_flash.c index fe47295..93058cb 100644 --- a/src/flash/stm32f4_flash.c +++ b/src/flash/stm32f4_flash.c @@ -146,8 +146,13 @@ whal_Error whal_Stm32f4_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t l (void)addr; (void)len; - whal_Reg_Write(base, FLASH_KEYR_REG, FLASH_KEY1); - whal_Reg_Write(base, FLASH_KEYR_REG, FLASH_KEY2); + if (whal_Reg_Read(base, FLASH_CR_REG) & FLASH_CR_LOCK_Msk) { + whal_Reg_Write(base, FLASH_KEYR_REG, FLASH_KEY1); + whal_Reg_Write(base, FLASH_KEYR_REG, FLASH_KEY2); + } + + if (whal_Reg_Read(base, FLASH_CR_REG) & FLASH_CR_LOCK_Msk) + return WHAL_EHARDWARE; return WHAL_SUCCESS; } diff --git a/src/flash/stm32h5_flash.c b/src/flash/stm32h5_flash.c index 70f24c5..debdc66 100644 --- a/src/flash/stm32h5_flash.c +++ b/src/flash/stm32h5_flash.c @@ -177,8 +177,13 @@ whal_Error whal_Stm32h5_Flash_Unlock(whal_Flash *flashDev, size_t addr, (void)addr; (void)len; - whal_Reg_Write(base, FLASH_NSKEYR_REG, FLASH_KEY1); - whal_Reg_Write(base, FLASH_NSKEYR_REG, FLASH_KEY2); + if (whal_Reg_Read(base, FLASH_NSCR_REG) & FLASH_NSCR_LOCK_Msk) { + whal_Reg_Write(base, FLASH_NSKEYR_REG, FLASH_KEY1); + whal_Reg_Write(base, FLASH_NSKEYR_REG, FLASH_KEY2); + } + + if (whal_Reg_Read(base, FLASH_NSCR_REG) & FLASH_NSCR_LOCK_Msk) + return WHAL_EHARDWARE; return WHAL_SUCCESS; } diff --git a/src/flash/stm32l1_flash.c b/src/flash/stm32l1_flash.c index 86194dd..01689fa 100644 --- a/src/flash/stm32l1_flash.c +++ b/src/flash/stm32l1_flash.c @@ -305,15 +305,18 @@ whal_Error whal_Stm32l1_Flash_Erase(whal_Flash *flashDev, size_t addr, whal_Error whal_Stm32l1_Flash_Ext_SetLatency(whal_Stm32l1_Flash_Latency latency) { - size_t val; + const whal_Stm32l1_Flash_Cfg *cfg = + (const whal_Stm32l1_Flash_Cfg *)whal_Stm32l1_Flash_Dev.cfg; + whal_Error err; whal_Reg_Update(FLASH_BASE_ADDR, FLASH_ACR_REG, FLASH_ACR_ACC64_Msk, whal_SetBits(FLASH_ACR_ACC64_Msk, FLASH_ACR_ACC64_Pos, 1)); - do { - whal_Reg_Get(FLASH_BASE_ADDR, FLASH_ACR_REG, - FLASH_ACR_ACC64_Msk, FLASH_ACR_ACC64_Pos, &val); - } while (!val); + err = whal_Reg_ReadPoll(FLASH_BASE_ADDR, FLASH_ACR_REG, + FLASH_ACR_ACC64_Msk, FLASH_ACR_ACC64_Msk, + cfg->timeout); + if (err) + return err; whal_Reg_Update(FLASH_BASE_ADDR, FLASH_ACR_REG, FLASH_ACR_PRFTEN_Msk, whal_SetBits(FLASH_ACR_PRFTEN_Msk, @@ -322,12 +325,11 @@ whal_Error whal_Stm32l1_Flash_Ext_SetLatency(whal_Stm32l1_Flash_Latency latency) whal_Reg_Update(FLASH_BASE_ADDR, FLASH_ACR_REG, FLASH_ACR_LATENCY_Msk, whal_SetBits(FLASH_ACR_LATENCY_Msk, FLASH_ACR_LATENCY_Pos, latency)); - do { - whal_Reg_Get(FLASH_BASE_ADDR, FLASH_ACR_REG, - FLASH_ACR_LATENCY_Msk, FLASH_ACR_LATENCY_Pos, &val); - } while (val != (size_t)latency); - - return WHAL_SUCCESS; + return whal_Reg_ReadPoll(FLASH_BASE_ADDR, FLASH_ACR_REG, + FLASH_ACR_LATENCY_Msk, + whal_SetBits(FLASH_ACR_LATENCY_Msk, + FLASH_ACR_LATENCY_Pos, latency), + cfg->timeout); } #ifndef WHAL_CFG_STM32L1_FLASH_DIRECT_API_MAPPING diff --git a/src/flash/stm32u5_flash.c b/src/flash/stm32u5_flash.c index 0602414..03d9b5b 100644 --- a/src/flash/stm32u5_flash.c +++ b/src/flash/stm32u5_flash.c @@ -141,8 +141,13 @@ whal_Error whal_Stm32u5_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t l (void)addr; (void)len; - whal_Reg_Write(base, FLASH_NSKEYR_REG, FLASH_KEY1); - whal_Reg_Write(base, FLASH_NSKEYR_REG, FLASH_KEY2); + if (whal_Reg_Read(base, FLASH_NSCR_REG) & FLASH_NSCR_LOCK_Msk) { + whal_Reg_Write(base, FLASH_NSKEYR_REG, FLASH_KEY1); + whal_Reg_Write(base, FLASH_NSKEYR_REG, FLASH_KEY2); + } + + if (whal_Reg_Read(base, FLASH_NSCR_REG) & FLASH_NSCR_LOCK_Msk) + return WHAL_EHARDWARE; return WHAL_SUCCESS; } diff --git a/src/flash/stm32wb_flash.c b/src/flash/stm32wb_flash.c index 50844dd..f97ba96 100644 --- a/src/flash/stm32wb_flash.c +++ b/src/flash/stm32wb_flash.c @@ -160,8 +160,13 @@ whal_Error whal_Stm32wb_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t l * Unlock sequence: write KEY1 then KEY2 to KEYR register. * Incorrect sequence or order will trigger a bus error. */ - whal_Reg_Update(base, FLASH_KEYR_REG, FLASH_KEYR_KEY_Msk, 0x45670123); - whal_Reg_Update(base, FLASH_KEYR_REG, FLASH_KEYR_KEY_Msk, 0xCDEF89AB); + if (whal_Reg_Read(base, FLASH_CR_REG) & FLASH_CR_LOCK_Msk) { + whal_Reg_Update(base, FLASH_KEYR_REG, FLASH_KEYR_KEY_Msk, 0x45670123); + whal_Reg_Update(base, FLASH_KEYR_REG, FLASH_KEYR_KEY_Msk, 0xCDEF89AB); + } + + if (whal_Reg_Read(base, FLASH_CR_REG) & FLASH_CR_LOCK_Msk) + return WHAL_EHARDWARE; return WHAL_SUCCESS; } @@ -246,6 +251,13 @@ static whal_Error whal_Stm32wb_Flash_WriteOrErase(whal_Flash *flashDev, size_t a FLASH_SR_CFGBSY_Msk, 0, cfg->timeout); if (err) goto cleanup; + + /* Check for errors */ + if (whal_Reg_Read(base, FLASH_SR_REG) & FLASH_SR_ALL_ERR) { + whal_Reg_Update(base, FLASH_SR_REG, FLASH_SR_ALL_ERR, FLASH_SR_ALL_ERR); + err = WHAL_EHARDWARE; + goto cleanup; + } } } else { @@ -273,16 +285,19 @@ static whal_Error whal_Stm32wb_Flash_WriteOrErase(whal_Flash *flashDev, size_t a FLASH_SR_CFGBSY_Msk, 0, cfg->timeout); if (err) goto cleanup; - } - /* Disable page erase mode */ - whal_Reg_Update(base, FLASH_CR_REG, FLASH_CR_PER_Msk, - whal_SetBits(FLASH_CR_PER_Msk, FLASH_CR_PER_Pos, 0)); + /* Check for errors */ + if (whal_Reg_Read(base, FLASH_SR_REG) & FLASH_SR_ALL_ERR) { + whal_Reg_Update(base, FLASH_SR_REG, FLASH_SR_ALL_ERR, FLASH_SR_ALL_ERR); + err = WHAL_EHARDWARE; + goto cleanup; + } + } } cleanup: - /* Disable flash programming mode */ - whal_Reg_Update(base, FLASH_CR_REG, FLASH_CR_PG_Msk, 0); + /* Disable flash programming and page erase modes */ + whal_Reg_Update(base, FLASH_CR_REG, FLASH_CR_PG_Msk | FLASH_CR_PER_Msk, 0); return err; } diff --git a/src/flash/stm32wba_flash.c b/src/flash/stm32wba_flash.c index 2206ee6..f4ba2b6 100644 --- a/src/flash/stm32wba_flash.c +++ b/src/flash/stm32wba_flash.c @@ -144,6 +144,9 @@ whal_Error whal_Stm32wba_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t whal_Reg_Write(base, FLASH_NSKEYR_REG, FLASH_KEY2); } + if (whal_Reg_Read(base, FLASH_NSCR1_REG) & FLASH_NSCR1_LOCK_Msk) + return WHAL_EHARDWARE; + return WHAL_SUCCESS; } @@ -169,6 +172,12 @@ whal_Error whal_Stm32wba_Flash_Read(whal_Flash *flashDev, size_t addr, void *dat static whal_Error WaitNotBusy(size_t base, whal_Timeout *timeout) { + whal_Error err; + + /* WDW must be checked clear before BSY */ + err = whal_Reg_ReadPoll(base, FLASH_NSSR_REG, FLASH_NSSR_WDW_Msk, 0, timeout); + if (err) + return err; return whal_Reg_ReadPoll(base, FLASH_NSSR_REG, FLASH_NSSR_BSY_Msk, 0, timeout); } diff --git a/tests/flash/test_stm32wb_flash.c b/tests/flash/test_stm32wb_flash.c index 0c387ff..fe30007 100644 --- a/tests/flash/test_stm32wb_flash.c +++ b/tests/flash/test_stm32wb_flash.c @@ -42,7 +42,65 @@ static void Test_Flash_LockReadback(void) WHAL_ASSERT_EQ(val, 1); } +static void LockBlocksWrite(void) +{ + const uint8_t written[16] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + }; + const uint8_t attempted[16] = { + 0x5A, 0x5A, 0x5A, 0x5A, 0xA5, 0xA5, 0xA5, 0xA5, + 0x5A, 0x5A, 0x5A, 0x5A, 0xA5, 0xA5, 0xA5, 0xA5, + }; + uint8_t erased[16]; + uint8_t readback[16]; + whal_Error err; + size_t i; + + for (i = 0; i < sizeof(erased); i++) + erased[i] = 0xFF; + + WHAL_ASSERT_EQ(whal_Flash_Unlock(BOARD_FLASH_DEV, 0, 0), WHAL_SUCCESS); + WHAL_ASSERT_EQ(whal_Flash_Erase(BOARD_FLASH_DEV, BOARD_FLASH_TEST_ADDR, + BOARD_FLASH_SECTOR_SZ), WHAL_SUCCESS); + do { + err = whal_Flash_Write(BOARD_FLASH_DEV, BOARD_FLASH_TEST_ADDR, + written, sizeof(written)); + } while (err == WHAL_ENOTREADY); + WHAL_ASSERT_EQ(err, WHAL_SUCCESS); + + WHAL_ASSERT_EQ(whal_Flash_Lock(BOARD_FLASH_DEV, 0, 0), WHAL_SUCCESS); + + /* FLASH_CR is write-protected while locked, so PG stays clear and the + * programming attempt raises PGSERR */ + WHAL_ASSERT_EQ(whal_Flash_Write(BOARD_FLASH_DEV, + BOARD_FLASH_TEST_ADDR + sizeof(written), + attempted, sizeof(attempted)), + WHAL_EHARDWARE); + + WHAL_ASSERT_EQ(whal_Flash_Read(BOARD_FLASH_DEV, BOARD_FLASH_TEST_ADDR, + readback, sizeof(readback)), WHAL_SUCCESS); + WHAL_ASSERT_MEM_EQ(readback, written, sizeof(written)); + + WHAL_ASSERT_EQ(whal_Flash_Read(BOARD_FLASH_DEV, + BOARD_FLASH_TEST_ADDR + sizeof(written), + readback, sizeof(readback)), WHAL_SUCCESS); + WHAL_ASSERT_MEM_EQ(readback, erased, sizeof(erased)); +} + +static void Test_Flash_LockBlocksWrite(void) +{ + LockBlocksWrite(); + + /* Leave the test sector erased and the flash locked */ + whal_Flash_Unlock(BOARD_FLASH_DEV, 0, 0); + whal_Flash_Erase(BOARD_FLASH_DEV, BOARD_FLASH_TEST_ADDR, + BOARD_FLASH_SECTOR_SZ); + whal_Flash_Lock(BOARD_FLASH_DEV, 0, 0); +} + void whal_Test_Flash_Platform(void) { WHAL_TEST(Test_Flash_LockReadback); + WHAL_TEST(Test_Flash_LockBlocksWrite); } diff --git a/wolfHAL/flash/flash.h b/wolfHAL/flash/flash.h index 160b9ea..5302cda 100644 --- a/wolfHAL/flash/flash.h +++ b/wolfHAL/flash/flash.h @@ -83,11 +83,13 @@ whal_Error whal_Flash_Init(whal_Flash *flashDev); */ whal_Error whal_Flash_Deinit(whal_Flash *flashDev); /* - * @brief Lock a region of flash to prevent modification. + * @brief Lock flash to prevent modification. + * + * Current drivers lock the whole device and ignore @p addr and @p len. * * @param flashDev Flash instance to lock. - * @param addr Byte address in flash to lock. - * @param len Number of bytes to lock. + * @param addr Byte address of the region to lock (driver-defined). + * @param len Number of bytes to lock (driver-defined). * * @retval WHAL_SUCCESS Lock applied. * @retval WHAL_EINVAL Null pointer. @@ -95,11 +97,13 @@ whal_Error whal_Flash_Deinit(whal_Flash *flashDev); */ whal_Error whal_Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len); /* - * @brief Unlock a region of flash to allow modification. + * @brief Unlock flash to allow modification. + * + * Current drivers unlock the whole device and ignore @p addr and @p len. * * @param flashDev Flash instance to unlock. - * @param addr Byte address in flash to unlock. - * @param len Number of bytes to unlock. + * @param addr Byte address of the region to unlock (driver-defined). + * @param len Number of bytes to unlock (driver-defined). * * @retval WHAL_SUCCESS Unlock applied. * @retval WHAL_EINVAL Null pointer. diff --git a/wolfHAL/flash/stm32c0_flash.h b/wolfHAL/flash/stm32c0_flash.h index 74d38ef..8cb1095 100644 --- a/wolfHAL/flash/stm32c0_flash.h +++ b/wolfHAL/flash/stm32c0_flash.h @@ -112,8 +112,9 @@ whal_Error whal_Stm32c0_Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len * @param addr Unused. * @param len Unused. * - * @retval WHAL_SUCCESS Unlock applied. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_SUCCESS Unlock applied. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE LOCK still set after the key sequence. */ whal_Error whal_Stm32c0_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len); diff --git a/wolfHAL/flash/stm32f0_flash.h b/wolfHAL/flash/stm32f0_flash.h index 1bda2c6..ab8aa4f 100644 --- a/wolfHAL/flash/stm32f0_flash.h +++ b/wolfHAL/flash/stm32f0_flash.h @@ -106,7 +106,7 @@ whal_Error whal_Stm32f0_Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len * * @retval WHAL_SUCCESS Flash is unlocked. * @retval WHAL_EINVAL Null pointer. - * @retval WHAL_EHARDWARE Key sequence rejected (already unlocked or option-byte locked). + * @retval WHAL_EHARDWARE LOCK still set after the key sequence. */ whal_Error whal_Stm32f0_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len); diff --git a/wolfHAL/flash/stm32f4_flash.h b/wolfHAL/flash/stm32f4_flash.h index 1f98490..15e78d4 100644 --- a/wolfHAL/flash/stm32f4_flash.h +++ b/wolfHAL/flash/stm32f4_flash.h @@ -132,8 +132,9 @@ whal_Error whal_Stm32f4_Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len * @param addr Unused. * @param len Unused. * - * @retval WHAL_SUCCESS Unlock applied. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_SUCCESS Unlock applied. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE LOCK still set after the key sequence. */ whal_Error whal_Stm32f4_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len); diff --git a/wolfHAL/flash/stm32h5_flash.h b/wolfHAL/flash/stm32h5_flash.h index c0d9a4b..a08d6c6 100644 --- a/wolfHAL/flash/stm32h5_flash.h +++ b/wolfHAL/flash/stm32h5_flash.h @@ -96,8 +96,9 @@ whal_Error whal_Stm32h5_Flash_Lock(whal_Flash *flashDev, size_t addr, * @param addr Unused. * @param len Unused. * - * @retval WHAL_SUCCESS Unlock applied. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_SUCCESS Unlock applied. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE LOCK still set after the key sequence. */ whal_Error whal_Stm32h5_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len); diff --git a/wolfHAL/flash/stm32l1_flash.h b/wolfHAL/flash/stm32l1_flash.h index e2adeb2..030e6eb 100644 --- a/wolfHAL/flash/stm32l1_flash.h +++ b/wolfHAL/flash/stm32l1_flash.h @@ -186,7 +186,8 @@ whal_Error whal_Stm32l1_Flash_Erase(whal_Flash *flashDev, size_t addr, * * @param latency Desired latency (LATENCY_0 or LATENCY_1). * - * @retval WHAL_SUCCESS Latency updated. + * @retval WHAL_SUCCESS Latency updated. + * @retval WHAL_ETIMEOUT ACC64 or LATENCY did not read back in time. */ whal_Error whal_Stm32l1_Flash_Ext_SetLatency(whal_Stm32l1_Flash_Latency latency); diff --git a/wolfHAL/flash/stm32wb_flash.h b/wolfHAL/flash/stm32wb_flash.h index 225a376..4ff6fa7 100644 --- a/wolfHAL/flash/stm32wb_flash.h +++ b/wolfHAL/flash/stm32wb_flash.h @@ -102,25 +102,26 @@ whal_Error whal_Stm32wb_Flash_Init(whal_Flash *flashDev); */ whal_Error whal_Stm32wb_Flash_Deinit(whal_Flash *flashDev); /* - * @brief Lock a flash range. + * @brief Lock the flash for writes (sets FLASH_CR.LOCK). * * @param flashDev Flash device instance. - * @param addr Flash address to lock. - * @param len Number of bytes to lock. + * @param addr Unused; the whole flash is locked. + * @param len Unused. * * @retval WHAL_SUCCESS Lock applied. * @retval WHAL_EINVAL Invalid arguments. */ whal_Error whal_Stm32wb_Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len); /* - * @brief Unlock a flash range. + * @brief Unlock the flash for writes via the KEYR sequence. * * @param flashDev Flash device instance. - * @param addr Flash address to unlock. - * @param len Number of bytes to unlock. + * @param addr Unused; the whole flash is unlocked. + * @param len Unused. * - * @retval WHAL_SUCCESS Unlock applied. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_SUCCESS Unlock applied. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE LOCK still set after the key sequence. */ whal_Error whal_Stm32wb_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len); /* From 0b0037bd5acfde680cb4b32a51f1ed1d7143a939 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 11:37:41 -0400 Subject: [PATCH 04/18] [flash, stm32wb, stm32c0, stm32wba, stm32h5, stm32u5, stm32f4] Fix write alignment checks and source/destination access - WB: require 8-byte addr/dataSz for writes only (was 16-byte, applied to erase, and never checked dataSz) - Read the source buffer bytewise via new whal_LoadLe32 so unaligned buffers no longer fault (C0 Cortex-M0+) (WB, C0, WBA, H5, U5, F4) - Program flash through volatile pointers (WB, C0, WBA, H5, F4) --- src/flash/stm32c0_flash.c | 8 ++++---- src/flash/stm32f4_flash.c | 6 +++--- src/flash/stm32h5_flash.c | 12 ++++++------ src/flash/stm32u5_flash.c | 10 +++++----- src/flash/stm32wb_flash.c | 16 +++++++++------- src/flash/stm32wba_flash.c | 12 ++++++------ wolfHAL/endian.h | 9 +++++++++ 7 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/flash/stm32c0_flash.c b/src/flash/stm32c0_flash.c index 5ac0f61..834193f 100644 --- a/src/flash/stm32c0_flash.c +++ b/src/flash/stm32c0_flash.c @@ -27,6 +27,7 @@ #include #include #include +#include const whal_Flash whal_Stm32c0_Flash_Dev = WHAL_CFG_STM32C0_FLASH_DEV; @@ -238,12 +239,11 @@ static whal_Error whal_Stm32c0_Flash_WriteOrErase(whal_Flash *flashDev, size_t a /* Program data in 64-bit (8 byte) double-word chunks */ for (size_t i = 0; i < dataSz; i += 8) { - uint32_t *flashAddr = (uint32_t *)(addr + i); - uint32_t *dataAddr = (uint32_t *)(data + i); + volatile uint32_t *flashAddr = (volatile uint32_t *)(addr + i); /* Write both 32-bit words to trigger the 64-bit programming */ - flashAddr[0] = dataAddr[0]; - flashAddr[1] = dataAddr[1]; + flashAddr[0] = whal_LoadLe32(data + i); + flashAddr[1] = whal_LoadLe32(data + i + 4); /* Wait for programming to complete */ err = whal_Reg_ReadPoll(base, FLASH_SR_REG, diff --git a/src/flash/stm32f4_flash.c b/src/flash/stm32f4_flash.c index 93058cb..60cbb2c 100644 --- a/src/flash/stm32f4_flash.c +++ b/src/flash/stm32f4_flash.c @@ -27,6 +27,7 @@ #include #include #include +#include const whal_Flash whal_Stm32f4_Flash_Dev = WHAL_CFG_STM32F4_FLASH_DEV; @@ -215,10 +216,9 @@ whal_Error whal_Stm32f4_Flash_Write(whal_Flash *flashDev, size_t addr, /* Program data in 32-bit word chunks */ for (size_t i = 0; i < dataSz; i += 4) { - uint32_t *flashAddr = (uint32_t *)(addr + i); - const uint32_t *dataAddr = (const uint32_t *)(dataBuf + i); + volatile uint32_t *flashAddr = (volatile uint32_t *)(addr + i); - *flashAddr = *dataAddr; + *flashAddr = whal_LoadLe32(dataBuf + i); /* Wait for programming to complete */ err = whal_Reg_ReadPoll(base, FLASH_SR_REG, FLASH_SR_BSY_Msk, diff --git a/src/flash/stm32h5_flash.c b/src/flash/stm32h5_flash.c index debdc66..031858b 100644 --- a/src/flash/stm32h5_flash.c +++ b/src/flash/stm32h5_flash.c @@ -27,6 +27,7 @@ #include #include #include +#include const whal_Flash whal_Stm32h5_Flash_Dev = WHAL_CFG_STM32H5_FLASH_DEV; @@ -260,13 +261,12 @@ whal_Error whal_Stm32h5_Flash_Write(whal_Flash *flashDev, size_t addr, /* Program data in 128-bit (16 byte) flash-word chunks */ for (size_t i = 0; i < dataSz; i += 16) { - uint32_t *flashAddr = (uint32_t *)(addr + i); - const uint32_t *dataAddr = (const uint32_t *)(dataBuf + i); + volatile uint32_t *flashAddr = (volatile uint32_t *)(addr + i); - flashAddr[0] = dataAddr[0]; - flashAddr[1] = dataAddr[1]; - flashAddr[2] = dataAddr[2]; - flashAddr[3] = dataAddr[3]; + flashAddr[0] = whal_LoadLe32(dataBuf + i); + flashAddr[1] = whal_LoadLe32(dataBuf + i + 4); + flashAddr[2] = whal_LoadLe32(dataBuf + i + 8); + flashAddr[3] = whal_LoadLe32(dataBuf + i + 12); err = WaitNotBusy(base, cfg->timeout); if (err) diff --git a/src/flash/stm32u5_flash.c b/src/flash/stm32u5_flash.c index 03d9b5b..0b903dc 100644 --- a/src/flash/stm32u5_flash.c +++ b/src/flash/stm32u5_flash.c @@ -27,6 +27,7 @@ #include #include #include +#include const whal_Flash whal_Stm32u5_Flash_Dev = WHAL_CFG_STM32U5_FLASH_DEV; @@ -228,12 +229,11 @@ whal_Error whal_Stm32u5_Flash_Write(whal_Flash *flashDev, size_t addr, * reorder or merge non-volatile stores into LDM/STM or memcpy. */ for (size_t i = 0; i < dataSz; i += 16) { volatile uint32_t *flashAddr = (volatile uint32_t *)(addr + i); - const uint32_t *dataAddr = (const uint32_t *)(dataBuf + i); - flashAddr[0] = dataAddr[0]; - flashAddr[1] = dataAddr[1]; - flashAddr[2] = dataAddr[2]; - flashAddr[3] = dataAddr[3]; + flashAddr[0] = whal_LoadLe32(dataBuf + i); + flashAddr[1] = whal_LoadLe32(dataBuf + i + 4); + flashAddr[2] = whal_LoadLe32(dataBuf + i + 8); + flashAddr[3] = whal_LoadLe32(dataBuf + i + 12); err = WaitNotBusy(base, cfg->timeout); if (err) diff --git a/src/flash/stm32wb_flash.c b/src/flash/stm32wb_flash.c index f97ba96..122e0eb 100644 --- a/src/flash/stm32wb_flash.c +++ b/src/flash/stm32wb_flash.c @@ -27,6 +27,7 @@ #include #include #include +#include const whal_Flash whal_Stm32wb_Flash_Dev = WHAL_CFG_STM32WB_FLASH_DEV; @@ -215,10 +216,12 @@ static whal_Error whal_Stm32wb_Flash_WriteOrErase(whal_Flash *flashDev, size_t a if (dataSz == 0) return WHAL_SUCCESS; - /* Validate address alignment and bounds */ - if (addr & 0xf || addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) { + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + + /* Write requires 8-byte alignment (64-bit double-word programming) */ + if (write && ((addr & 0x7) || (dataSz & 0x7))) return WHAL_EINVAL; - } /* Check if flash is busy or suspended */ whal_Reg_Get(base, FLASH_SR_REG, FLASH_SR_BSY_Msk, FLASH_SR_BSY_Pos, &bsy); @@ -239,12 +242,11 @@ static whal_Error whal_Stm32wb_Flash_WriteOrErase(whal_Flash *flashDev, size_t a /* Program data in 64-bit (8 byte) double-word chunks */ for (size_t i = 0; i < dataSz; i += 8) { - uint32_t *flashAddr = (uint32_t *)(addr + i); - uint32_t *dataAddr = (uint32_t *)(data + i); + volatile uint32_t *flashAddr = (volatile uint32_t *)(addr + i); /* Write both 32-bit words to trigger the 64-bit programming */ - flashAddr[0] = dataAddr[0]; - flashAddr[1] = dataAddr[1]; + flashAddr[0] = whal_LoadLe32(data + i); + flashAddr[1] = whal_LoadLe32(data + i + 4); /* Wait for programming to complete */ err = whal_Reg_ReadPoll(base, FLASH_SR_REG, diff --git a/src/flash/stm32wba_flash.c b/src/flash/stm32wba_flash.c index f4ba2b6..da779f1 100644 --- a/src/flash/stm32wba_flash.c +++ b/src/flash/stm32wba_flash.c @@ -27,6 +27,7 @@ #include #include #include +#include const whal_Flash whal_Stm32wba_Flash_Dev = WHAL_CFG_STM32WBA_FLASH_DEV; @@ -226,13 +227,12 @@ whal_Error whal_Stm32wba_Flash_Write(whal_Flash *flashDev, size_t addr, /* Program in 128-bit (16 byte) flash-word chunks */ for (size_t i = 0; i < dataSz; i += 16) { - uint32_t *flashAddr = (uint32_t *)(addr + i); - const uint32_t *dataAddr = (const uint32_t *)(dataBuf + i); + volatile uint32_t *flashAddr = (volatile uint32_t *)(addr + i); - flashAddr[0] = dataAddr[0]; - flashAddr[1] = dataAddr[1]; - flashAddr[2] = dataAddr[2]; - flashAddr[3] = dataAddr[3]; + flashAddr[0] = whal_LoadLe32(dataBuf + i); + flashAddr[1] = whal_LoadLe32(dataBuf + i + 4); + flashAddr[2] = whal_LoadLe32(dataBuf + i + 8); + flashAddr[3] = whal_LoadLe32(dataBuf + i + 12); err = WaitNotBusy(base, cfg->timeout); if (err) diff --git a/wolfHAL/endian.h b/wolfHAL/endian.h index 0e939aa..9dddf81 100644 --- a/wolfHAL/endian.h +++ b/wolfHAL/endian.h @@ -39,6 +39,15 @@ static inline uint32_t whal_LoadBe32(const uint8_t *p) ((uint32_t)p[2] << 8) | p[3]; } +/* + * @brief Load a 32-bit value from a little-endian byte array. + */ +static inline uint32_t whal_LoadLe32(const uint8_t *p) +{ + return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | + ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); +} + /* * @brief Store a 32-bit value into a big-endian byte array. */ From 1a1aafbe7488baa26ed4ea6e27b2b81420870d81 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 11:57:18 -0400 Subject: [PATCH 05/18] [flash, pic32cz, stm32f411, test] Bound PIC32CZ flash ops, fix error codes, add out-of-bounds test - PIC32CZ: reject Read/Write/Erase outside the flash region, return early on zero-length erase, report controller errors as EHARDWARE, read the source bytewise via whal_LoadLe32 - Document PIC32CZ Lock as applying no protection - Add a generic on-chip test that out-of-region Read/Write/Erase return EINVAL; add flash region macros for PIC32CZ and F411 --- .../pic32cz_curiosity_ultra/wolfHAL_board.h | 8 ++-- boards/stm32f411_blackpill/wolfHAL_board.h | 3 ++ src/flash/pic32cz_flash.c | 31 +++++++++------ tests/flash/test_flash.c | 39 +++++++++++++++++-- wolfHAL/flash/pic32cz_flash.h | 20 +++++----- 5 files changed, 75 insertions(+), 26 deletions(-) diff --git a/boards/pic32cz_curiosity_ultra/wolfHAL_board.h b/boards/pic32cz_curiosity_ultra/wolfHAL_board.h index 8b9e282..df56752 100644 --- a/boards/pic32cz_curiosity_ultra/wolfHAL_board.h +++ b/boards/pic32cz_curiosity_ultra/wolfHAL_board.h @@ -33,9 +33,11 @@ extern whal_Timeout g_whalTimeout; extern volatile uint32_t g_tick; -#define BOARD_LED_PIN 0 -#define BOARD_FLASH_TEST_ADDR 0x0C000000 -#define BOARD_FLASH_SECTOR_SZ 0x1000 +#define BOARD_LED_PIN 0 +#define BOARD_FLASH_START_ADDR 0x0C000000 +#define BOARD_FLASH_SIZE 0x00800000 +#define BOARD_FLASH_TEST_ADDR 0x0C000000 +#define BOARD_FLASH_SECTOR_SZ 0x1000 /* BOARD_*_DEV: how this board reaches each peripheral. */ #define BOARD_GPIO_DEV WHAL_INTERNAL_DEV diff --git a/boards/stm32f411_blackpill/wolfHAL_board.h b/boards/stm32f411_blackpill/wolfHAL_board.h index 2e97906..5af7e78 100644 --- a/boards/stm32f411_blackpill/wolfHAL_board.h +++ b/boards/stm32f411_blackpill/wolfHAL_board.h @@ -45,6 +45,9 @@ enum { #define BOARD_LED_PIN 0 +#define BOARD_FLASH_START_ADDR 0x08000000 +#define BOARD_FLASH_SIZE 0x80000 + /* Flash test address: last sector (sector 7, 128KB at 0x08060000) */ #define BOARD_FLASH_TEST_ADDR 0x08060000 #define BOARD_FLASH_SECTOR_SZ 0x20000 diff --git a/src/flash/pic32cz_flash.c b/src/flash/pic32cz_flash.c index 65fe143..4e53d63 100644 --- a/src/flash/pic32cz_flash.c +++ b/src/flash/pic32cz_flash.c @@ -27,6 +27,7 @@ #include #include #include +#include const whal_Flash whal_Pic32cz_Flash_Dev = WHAL_CFG_PIC32CZ_FLASH_DEV; @@ -197,7 +198,7 @@ static whal_Error whal_Pic32cz_Flash_ExecCmd(size_t base, size_t cmd, /* Clear error flags */ whal_Reg_Update(base, FCW_INTFLAG_REG, FCW_INTFLAG_ALL_ERR, FCW_INTFLAG_ALL_ERR); - return WHAL_EINVAL; + return WHAL_EHARDWARE; } return WHAL_SUCCESS; @@ -276,6 +277,9 @@ whal_Error whal_Pic32cz_Flash_Read(whal_Flash *flashDev, size_t addr, void *data return WHAL_EINVAL; } + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + err = whal_Pic32cz_Flash_MutexLock(base, cfg->timeout); if (err) return err; @@ -297,7 +301,6 @@ whal_Error whal_Pic32cz_Flash_Write(whal_Flash *flashDev, size_t addr, const voi (const whal_Pic32cz_Flash_Cfg *)whal_Pic32cz_Flash_Dev.cfg; size_t base = whal_Pic32cz_Flash_Dev.base; const uint8_t *dataBuf = (const uint8_t *)data; - const uint32_t *src; whal_Error err; size_t offset = 0; (void)flashDev; @@ -306,14 +309,14 @@ whal_Error whal_Pic32cz_Flash_Write(whal_Flash *flashDev, size_t addr, const voi return WHAL_EINVAL; } + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + /* Require double-word alignment */ if ((addr & 0x7) || (dataSz & 0x7)) { return WHAL_EINVAL; } - src = (const uint32_t *)dataBuf; - - err = whal_Pic32cz_Flash_MutexLock(base, cfg->timeout); if (err) return err; @@ -332,8 +335,8 @@ whal_Error whal_Pic32cz_Flash_Write(whal_Flash *flashDev, size_t addr, const voi /* Quad double word write (32 bytes) */ size_t j; for (j = 0; j < 8; j++) { - whal_Reg_Update(base, FCW_DATA_REG(j), - 0xFFFFFFFF, src[offset / 4 + j]); + whal_Reg_Update(base, FCW_DATA_REG(j), 0xFFFFFFFF, + whal_LoadLe32(dataBuf + offset + j * 4)); } whal_Reg_Update(base, FCW_ADDR_REG, 0xFFFFFFFF, curAddr); @@ -347,10 +350,10 @@ whal_Error whal_Pic32cz_Flash_Write(whal_Flash *flashDev, size_t addr, const voi offset += FCW_QDWORD_SIZE; } else { /* Single double word write (8 bytes) */ - whal_Reg_Update(base, FCW_DATA_REG(0), - 0xFFFFFFFF, src[offset / 4]); - whal_Reg_Update(base, FCW_DATA_REG(1), - 0xFFFFFFFF, src[offset / 4 + 1]); + whal_Reg_Update(base, FCW_DATA_REG(0), 0xFFFFFFFF, + whal_LoadLe32(dataBuf + offset)); + whal_Reg_Update(base, FCW_DATA_REG(1), 0xFFFFFFFF, + whal_LoadLe32(dataBuf + offset + 4)); whal_Reg_Update(base, FCW_ADDR_REG, 0xFFFFFFFF, curAddr); err = whal_Pic32cz_Flash_ExecCmd(base, @@ -380,6 +383,12 @@ whal_Error whal_Pic32cz_Flash_Erase(whal_Flash *flashDev, size_t addr, size_t da size_t endAddr; (void)flashDev; + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + + if (dataSz == 0) + return WHAL_SUCCESS; + /* Align down to page boundary */ pageAddr = addr & ~(FCW_PAGE_SIZE - 1); endAddr = addr + dataSz; diff --git a/tests/flash/test_flash.c b/tests/flash/test_flash.c index 722ecaf..744ac88 100644 --- a/tests/flash/test_flash.c +++ b/tests/flash/test_flash.c @@ -78,13 +78,46 @@ static void Test_Flash_WriteReadErase(void) g_testFlashSectorSz), WHAL_SUCCESS); } -static void run_flash_tests(const char *name) +static void Test_Flash_OutOfBounds(void) +{ + const size_t start = BOARD_FLASH_START_ADDR; + const size_t end = BOARD_FLASH_START_ADDR + BOARD_FLASH_SIZE; + static uint8_t buf[32]; + + /* Below the region */ + WHAL_ASSERT_EQ(whal_Flash_Read(g_testFlashDev, start - 16, buf, 16), + WHAL_EINVAL); + WHAL_ASSERT_EQ(whal_Flash_Write(g_testFlashDev, start - 16, buf, 16), + WHAL_EINVAL); + WHAL_ASSERT_EQ(whal_Flash_Erase(g_testFlashDev, start - 16, 16), + WHAL_EINVAL); + + /* Starting at the end of the region */ + WHAL_ASSERT_EQ(whal_Flash_Read(g_testFlashDev, end, buf, 16), + WHAL_EINVAL); + WHAL_ASSERT_EQ(whal_Flash_Write(g_testFlashDev, end, buf, 16), + WHAL_EINVAL); + WHAL_ASSERT_EQ(whal_Flash_Erase(g_testFlashDev, end, 16), + WHAL_EINVAL); + + /* Starting inside the region and running past the end */ + WHAL_ASSERT_EQ(whal_Flash_Read(g_testFlashDev, end - 16, buf, 32), + WHAL_EINVAL); + WHAL_ASSERT_EQ(whal_Flash_Write(g_testFlashDev, end - 16, buf, 32), + WHAL_EINVAL); + WHAL_ASSERT_EQ(whal_Flash_Erase(g_testFlashDev, end - 16, 32), + WHAL_EINVAL); +} + +static void run_flash_tests(const char *name, int onChip) { WHAL_TEST_SUITE_START("flash"); if (name) whal_Test_Printf(" device: %s\n", name); WHAL_TEST(Test_Flash_Api); WHAL_TEST(Test_Flash_WriteReadErase); + if (onChip) + WHAL_TEST(Test_Flash_OutOfBounds); WHAL_TEST_SUITE_END(); } @@ -94,13 +127,13 @@ void whal_Test_Flash(void) g_testFlashDev = BOARD_FLASH_DEV; g_testFlashAddr = BOARD_FLASH_TEST_ADDR; g_testFlashSectorSz = BOARD_FLASH_SECTOR_SZ; - run_flash_tests("on-chip"); + run_flash_tests("on-chip", 1); /* Test peripheral flash devices */ for (size_t i = 0; g_peripheralFlash[i].dev; i++) { g_testFlashDev = g_peripheralFlash[i].dev; g_testFlashAddr = 0; g_testFlashSectorSz = g_peripheralFlash[i].sectorSz; - run_flash_tests(g_peripheralFlash[i].name); + run_flash_tests(g_peripheralFlash[i].name, 0); } } diff --git a/wolfHAL/flash/pic32cz_flash.h b/wolfHAL/flash/pic32cz_flash.h index cfc7f61..f177d35 100644 --- a/wolfHAL/flash/pic32cz_flash.h +++ b/wolfHAL/flash/pic32cz_flash.h @@ -83,13 +83,13 @@ whal_Error whal_Pic32cz_Flash_Init(whal_Flash *flashDev); */ whal_Error whal_Pic32cz_Flash_Deinit(whal_Flash *flashDev); /* - * @brief Lock a flash range (stub, not yet implemented). + * @brief Lock flash (stub; no write protection is applied yet). * * @param flashDev Flash device instance. - * @param addr Flash address to lock. - * @param len Number of bytes to lock. + * @param addr Unused. + * @param len Unused. * - * @retval WHAL_SUCCESS Lock applied. + * @retval WHAL_SUCCESS Always; flash remains writable. * @retval WHAL_EINVAL Invalid arguments. */ whal_Error whal_Pic32cz_Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len); @@ -113,7 +113,7 @@ whal_Error whal_Pic32cz_Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t l * @param dataSz Number of bytes to read. * * @retval WHAL_SUCCESS Read completed. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EINVAL Invalid arguments or range outside the flash region. */ whal_Error whal_Pic32cz_Flash_Read(whal_Flash *flashDev, size_t addr, void *data, size_t dataSz); @@ -129,8 +129,9 @@ whal_Error whal_Pic32cz_Flash_Read(whal_Flash *flashDev, size_t addr, void *data * @param data Buffer to program (8-byte aligned). * @param dataSz Number of bytes to program (multiple of 8). * - * @retval WHAL_SUCCESS Program completed. - * @retval WHAL_EINVAL Invalid arguments or alignment. + * @retval WHAL_SUCCESS Program completed. + * @retval WHAL_EINVAL Invalid arguments, alignment, or range outside the flash region. + * @retval WHAL_EHARDWARE Flash controller reported an error. */ whal_Error whal_Pic32cz_Flash_Write(whal_Flash *flashDev, size_t addr, const void *data, size_t dataSz); @@ -143,8 +144,9 @@ whal_Error whal_Pic32cz_Flash_Write(whal_Flash *flashDev, size_t addr, const voi * @param addr Flash address to start erasing. * @param dataSz Number of bytes to erase. * - * @retval WHAL_SUCCESS Erase completed. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_SUCCESS Erase completed. + * @retval WHAL_EINVAL Invalid arguments or range outside the flash region. + * @retval WHAL_EHARDWARE Flash controller reported an error. */ whal_Error whal_Pic32cz_Flash_Erase(whal_Flash *flashDev, size_t addr, size_t dataSz); #endif /* !WHAL_CFG_PIC32CZ_FLASH_DIRECT_API_MAPPING */ From 603b9d7c303b42428c89ced9320bfefcf4f26dc0 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 12:25:32 -0400 Subject: [PATCH 06/18] [eth, stm32h5, stm32n6, lan8742a] Bound Ethernet RX, add DMA barriers, fix PHY MDIO device - Drop RX frames that have errors, span multiple buffers, or report a length larger than the RX buffer (H5, N6) - Add dsb before DMA tail-pointer kicks on H5 and the N6 RX error path - Validate speed and duplex in Start (H5, N6) - LAN8742A: route MDIO through the configured MAC instead of NULL; power the PHY down in Deinit - Fix PHY Init, N6 Send, and N6/H5 IP description docs --- src/eth/stm32h5_eth.c | 23 +++++++++++++++++++++-- src/eth/stm32n6_eth.c | 21 +++++++++++++++++---- src/eth_phy/lan8742a_eth_phy.c | 25 +++++++++++++++++-------- wolfHAL/eth/stm32h5_eth.h | 2 +- wolfHAL/eth/stm32n6_eth.h | 11 +++++++---- wolfHAL/eth_phy/eth_phy.h | 9 ++++++--- wolfHAL/eth_phy/lan8742a_eth_phy.h | 9 +++++---- 7 files changed, 74 insertions(+), 26 deletions(-) diff --git a/src/eth/stm32h5_eth.c b/src/eth/stm32h5_eth.c index 44580b2..06e1693 100644 --- a/src/eth/stm32h5_eth.c +++ b/src/eth/stm32h5_eth.c @@ -142,6 +142,8 @@ static struct { /* --- RX descriptor bits (RDES3) --- */ #define RDES3_OWN (1UL << 31) #define RDES3_IOC (1UL << 30) +#define RDES3_FD (1UL << 29) +#define RDES3_LD (1UL << 28) #define RDES3_BUF1V (1UL << 24) #define RDES3_ES (1UL << 15) #define RDES3_PL_Msk 0x7FFFUL @@ -250,6 +252,9 @@ whal_Error whal_Stm32h5_Eth_Init(whal_Eth *ethDev) eth_state.txHead = 0; eth_state.rxHead = 0; + /* Make the descriptor rings visible before Start() kicks the DMA */ + __asm__ volatile ("dsb sy" ::: "memory"); + return WHAL_SUCCESS; } @@ -270,6 +275,10 @@ whal_Error whal_Stm32h5_Eth_Start(whal_Eth *ethDev, uint8_t speed, size_t base = whal_Stm32h5_Eth_Dev.base; (void)ethDev; + if ((speed != WHAL_ETH_SPEED_10 && speed != WHAL_ETH_SPEED_100) || + (duplex != WHAL_ETH_DUPLEX_HALF && duplex != WHAL_ETH_DUPLEX_FULL)) + return WHAL_EINVAL; + /* Configure MAC speed and duplex to match PHY */ whal_Reg_Update(base, ETH_MACCR_REG, ETH_MACCR_FES_Msk | ETH_MACCR_DM_Msk, @@ -348,6 +357,9 @@ whal_Error whal_Stm32h5_Eth_Send(whal_Eth *ethDev, const void *frame, /* Advance ring position */ eth_state.txHead = (idx + 1) % cfg->txDescCount; + /* Order the descriptor writes before the tail-pointer kick */ + __asm__ volatile ("dsb sy" ::: "memory"); + /* Kick DMA — tail pointer past the end of the ring */ whal_Reg_Write(base, ETH_DMACTXDTPR_REG, (uintptr_t)&cfg->txDescs[cfg->txDescCount]); @@ -380,11 +392,15 @@ whal_Error whal_Stm32h5_Eth_Recv(whal_Eth *ethDev, void *frame, if (rdes3 & RDES3_OWN) return WHAL_ENOTREADY; - /* Check for errors */ - if (rdes3 & RDES3_ES) { + /* Drop errored frames, frames spanning several buffers, and lengths + * larger than the buffer */ + if ((rdes3 & RDES3_ES) || + (rdes3 & (RDES3_FD | RDES3_LD)) != (RDES3_FD | RDES3_LD) || + (rdes3 & RDES3_PL_Msk) > cfg->rxBufSize) { desc->des[0] = (uintptr_t)(cfg->rxBufs + idx * cfg->rxBufSize); desc->des[3] = RDES3_OWN | RDES3_IOC | RDES3_BUF1V; eth_state.rxHead = (idx + 1) % cfg->rxDescCount; + __asm__ volatile ("dsb sy" ::: "memory"); whal_Reg_Write(base, ETH_DMACRXDTPR_REG, (uintptr_t)&cfg->rxDescs[cfg->rxDescCount]); return WHAL_EHARDWARE; @@ -412,6 +428,9 @@ whal_Error whal_Stm32h5_Eth_Recv(whal_Eth *ethDev, void *frame, /* Advance ring position */ eth_state.rxHead = (idx + 1) % cfg->rxDescCount; + /* Order the OWN=1 re-arm write before the tail-pointer kick */ + __asm__ volatile ("dsb sy" ::: "memory"); + /* Update RX tail pointer — always past end of ring */ whal_Reg_Write(base, ETH_DMACRXDTPR_REG, (uintptr_t)&cfg->rxDescs[cfg->rxDescCount]); diff --git a/src/eth/stm32n6_eth.c b/src/eth/stm32n6_eth.c index 3bd53ed..91c230e 100644 --- a/src/eth/stm32n6_eth.c +++ b/src/eth/stm32n6_eth.c @@ -39,8 +39,11 @@ static struct { * @file stm32n6_eth.c * @brief STM32N6 Ethernet MAC driver implementation. * - * The STM32N6 uses the Synopsys DWC EQOS GMAC with AXI 64-bit bus. - * Register layout matches the STM32H5 except for: + * The STM32N6 uses the gigabit (GMAC) configuration of the Synopsys DWC EQOS + * with an AXI 64-bit bus. It shares the STM32H5's EQOS register family; + * differences relevant to this driver include: + * - MACCR bit 15 is PS (port select); reserved on the H5 + * - MTL RX queue 0 must be enabled (MACRXQC0R.RXQ0EN) * - AXI coherency registers at DMA offsets 0x1020-0x1028 * - 2 DMA channels at 0x80 stride (this driver uses channel 0 only) * - Descriptor alignment: bits 2:0 reserved (8-byte aligned) @@ -154,6 +157,8 @@ static struct { /* --- RX descriptor bits (RDES3) --- */ #define RDES3_OWN (1UL << 31) #define RDES3_IOC (1UL << 30) +#define RDES3_FD (1UL << 29) +#define RDES3_LD (1UL << 28) #define RDES3_BUF1V (1UL << 24) #define RDES3_ES (1UL << 15) #define RDES3_PL_Msk 0x7FFFUL @@ -301,6 +306,10 @@ whal_Error whal_Stm32n6_Eth_Start(whal_Eth *ethDev, uint8_t speed, size_t base = whal_Stm32n6_Eth_Dev.base; (void)ethDev; + if ((speed != WHAL_ETH_SPEED_10 && speed != WHAL_ETH_SPEED_100) || + (duplex != WHAL_ETH_DUPLEX_HALF && duplex != WHAL_ETH_DUPLEX_FULL)) + return WHAL_EINVAL; + /* Configure MAC speed and duplex to match PHY. PS=1 selects the * MII/RMII data path; required because the EQOS MAC defaults to GMII * (PS=0) and this driver only supports 10/100 Mbps. */ @@ -422,11 +431,15 @@ whal_Error whal_Stm32n6_Eth_Recv(whal_Eth *ethDev, void *frame, if (rdes3 & RDES3_OWN) return WHAL_ENOTREADY; - /* Check for errors */ - if (rdes3 & RDES3_ES) { + /* Drop errored frames, frames spanning several buffers, and lengths + * larger than the buffer */ + if ((rdes3 & RDES3_ES) || + (rdes3 & (RDES3_FD | RDES3_LD)) != (RDES3_FD | RDES3_LD) || + (rdes3 & RDES3_PL_Msk) > cfg->rxBufSize) { desc->des[0] = (uintptr_t)(cfg->rxBufs + idx * cfg->rxBufSize); desc->des[3] = RDES3_OWN | RDES3_IOC | RDES3_BUF1V; eth_state.rxHead = (idx + 1) % cfg->rxDescCount; + __asm__ volatile ("dsb sy" ::: "memory"); whal_Reg_Write(base, ETH_DMAC0RXDTPR_REG, (uintptr_t)&cfg->rxDescs[cfg->rxDescCount]); return WHAL_EHARDWARE; diff --git a/src/eth_phy/lan8742a_eth_phy.c b/src/eth_phy/lan8742a_eth_phy.c index 4179961..d18843c 100644 --- a/src/eth_phy/lan8742a_eth_phy.c +++ b/src/eth_phy/lan8742a_eth_phy.c @@ -33,6 +33,7 @@ const whal_EthPhy whal_Lan8742a_Dev = WHAL_CFG_LAN8742A_DEV; #define PHY_BCR 0x00 /* Basic Control Register */ #define PHY_BCR_RESET (1UL << 15) #define PHY_BCR_ANEN (1UL << 12) +#define PHY_BCR_PDOWN (1UL << 11) #define PHY_BSR 0x01 /* Basic Status Register */ #define PHY_BSR_LINK (1UL << 2) @@ -64,7 +65,7 @@ whal_Error whal_Lan8742a_Init(whal_EthPhy *phyDev) #endif /* Software reset */ - err = whal_Eth_MdioWrite(NULL, addr, PHY_BCR, PHY_BCR_RESET); + err = whal_Eth_MdioWrite(whal_Lan8742a_Dev.eth, addr, PHY_BCR, PHY_BCR_RESET); if (err) return err; @@ -73,17 +74,17 @@ whal_Error whal_Lan8742a_Init(whal_EthPhy *phyDev) do { if (WHAL_TIMEOUT_EXPIRED(cfg->timeout)) return WHAL_ETIMEOUT; - err = whal_Eth_MdioRead(NULL, addr, PHY_BCR, &val); + err = whal_Eth_MdioRead(whal_Lan8742a_Dev.eth, addr, PHY_BCR, &val); if (err) return err; } while (val & PHY_BCR_RESET); /* Enable autonegotiation */ - err = whal_Eth_MdioRead(NULL, addr, PHY_BCR, &val); + err = whal_Eth_MdioRead(whal_Lan8742a_Dev.eth, addr, PHY_BCR, &val); if (err) return err; val |= PHY_BCR_ANEN; - err = whal_Eth_MdioWrite(NULL, addr, PHY_BCR, val); + err = whal_Eth_MdioWrite(whal_Lan8742a_Dev.eth, addr, PHY_BCR, val); if (err) return err; @@ -92,8 +93,16 @@ whal_Error whal_Lan8742a_Init(whal_EthPhy *phyDev) whal_Error whal_Lan8742a_Deinit(whal_EthPhy *phyDev) { + uint8_t addr = whal_Lan8742a_Dev.addr; + whal_Error err; + uint16_t val; (void)phyDev; - return WHAL_SUCCESS; + + err = whal_Eth_MdioRead(whal_Lan8742a_Dev.eth, addr, PHY_BCR, &val); + if (err) + return err; + val |= PHY_BCR_PDOWN; + return whal_Eth_MdioWrite(whal_Lan8742a_Dev.eth, addr, PHY_BCR, val); } whal_Error whal_Lan8742a_GetLinkState(whal_EthPhy *phyDev, uint8_t *up, @@ -112,17 +121,17 @@ whal_Error whal_Lan8742a_GetLinkState(whal_EthPhy *phyDev, uint8_t *up, * BSR link bit is latching-low (IEEE 802.3). First read clears a * stale link-down event; second read gives current status. */ - err = whal_Eth_MdioRead(NULL, addr, PHY_BSR, &bsr); + err = whal_Eth_MdioRead(whal_Lan8742a_Dev.eth, addr, PHY_BSR, &bsr); if (err) return err; - err = whal_Eth_MdioRead(NULL, addr, PHY_BSR, &bsr); + err = whal_Eth_MdioRead(whal_Lan8742a_Dev.eth, addr, PHY_BSR, &bsr); if (err) return err; *up = (bsr & PHY_BSR_LINK) ? 1 : 0; if (*up) { - err = whal_Eth_MdioRead(NULL, addr, PHY_PHYSCSR, &scsr); + err = whal_Eth_MdioRead(whal_Lan8742a_Dev.eth, addr, PHY_PHYSCSR, &scsr); if (err) return err; uint16_t spd = scsr & PHY_PHYSCSR_SPEED_Msk; diff --git a/wolfHAL/eth/stm32h5_eth.h b/wolfHAL/eth/stm32h5_eth.h index 002cc42..7b9c3e1 100644 --- a/wolfHAL/eth/stm32h5_eth.h +++ b/wolfHAL/eth/stm32h5_eth.h @@ -115,7 +115,7 @@ whal_Error whal_Stm32h5_Eth_Deinit(whal_Eth *ethDev); * @param duplex Duplex mode: WHAL_ETH_DUPLEX_HALF or WHAL_ETH_DUPLEX_FULL. * * @retval WHAL_SUCCESS MAC started. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EINVAL Unsupported speed or duplex value. */ whal_Error whal_Stm32h5_Eth_Start(whal_Eth *ethDev, uint8_t speed, uint8_t duplex); diff --git a/wolfHAL/eth/stm32n6_eth.h b/wolfHAL/eth/stm32n6_eth.h index 2fa5287..a03d077 100644 --- a/wolfHAL/eth/stm32n6_eth.h +++ b/wolfHAL/eth/stm32n6_eth.h @@ -26,8 +26,11 @@ * @file stm32n6_eth.h * @brief STM32N6 Ethernet MAC driver configuration. * - * The STM32N6 Ethernet peripheral uses the same Synopsys DWC EQOS GMAC IP - * as the STM32H5, with these differences: + * The STM32N6 Ethernet peripheral is the gigabit (GMAC) configuration of the + * Synopsys DWC EQOS family; the STM32H5 uses the 10/100 MAC configuration. + * Differences relevant to this driver include: + * - MACCR bit 15 is PS (port select) on the N6 and reserved on the H5 + * - MTL RX queue 0 must be enabled (MACRXQC0R.RXQ0EN) * - AXI 64-bit bus (vs AHB 32-bit) with ACE coherency registers * - 2 DMA channels with 0x80 stride (this driver uses channel 0 only) * - Descriptor alignment: bits 2:0 reserved (8-byte aligned) @@ -120,7 +123,7 @@ whal_Error whal_Stm32n6_Eth_Deinit(whal_Eth *ethDev); * @param duplex 0 = half duplex, 1 = full duplex. * * @retval WHAL_SUCCESS TX/RX enabled. - * @retval WHAL_EINVAL Null pointer or unsupported speed. + * @retval WHAL_EINVAL Unsupported speed or duplex value. */ whal_Error whal_Stm32n6_Eth_Start(whal_Eth *ethDev, uint8_t speed, uint8_t duplex); @@ -139,7 +142,7 @@ whal_Error whal_Stm32n6_Eth_Stop(whal_Eth *ethDev); * @brief Send a single Ethernet frame via DMA. * * @param ethDev Ethernet device instance. - * @param frame Pointer to the frame to send (DMA-accessible memory). + * @param frame Frame to send; copied into the TX DMA buffer, so any memory works. * @param len Frame length in bytes. * * @retval WHAL_SUCCESS Frame queued for transmission. diff --git a/wolfHAL/eth_phy/eth_phy.h b/wolfHAL/eth_phy/eth_phy.h index 9288866..15027ff 100644 --- a/wolfHAL/eth_phy/eth_phy.h +++ b/wolfHAL/eth_phy/eth_phy.h @@ -42,7 +42,7 @@ typedef struct whal_EthPhy whal_EthPhy; * @brief Driver vtable for Ethernet PHY devices. */ typedef struct { - /* Reset PHY, configure autonegotiation, and wait for link. */ + /* Reset PHY and enable autonegotiation; does not wait for link. */ whal_Error (*Init)(whal_EthPhy *phyDev); /* Power down the PHY. */ whal_Error (*Deinit)(whal_EthPhy *phyDev); @@ -67,11 +67,14 @@ struct whal_EthPhy { /* * @brief Initialize an Ethernet PHY. * + * Resets the PHY and enables autonegotiation. Does not wait for link; poll + * whal_EthPhy_GetLinkState() for that. + * * @param phyDev PHY device instance. * - * @retval WHAL_SUCCESS PHY initialized and link established. + * @retval WHAL_SUCCESS PHY reset and autonegotiation enabled. * @retval WHAL_EINVAL Invalid arguments. - * @retval WHAL_ETIMEOUT Link did not come up within timeout. + * @retval WHAL_ETIMEOUT PHY reset did not complete within timeout. */ whal_Error whal_EthPhy_Init(whal_EthPhy *phyDev); /* diff --git a/wolfHAL/eth_phy/lan8742a_eth_phy.h b/wolfHAL/eth_phy/lan8742a_eth_phy.h index 21ceb64..509c302 100644 --- a/wolfHAL/eth_phy/lan8742a_eth_phy.h +++ b/wolfHAL/eth_phy/lan8742a_eth_phy.h @@ -56,20 +56,20 @@ extern const whal_EthPhyDriver whal_Lan8742a_Driver; /* * @brief Initialize the LAN8742A PHY. * - * Resets the PHY, configures autonegotiation, and waits for link. + * Resets the PHY and enables autonegotiation. Does not wait for link. * * @param phyDev PHY device instance. * - * @retval WHAL_SUCCESS PHY initialized. + * @retval WHAL_SUCCESS PHY reset and autonegotiation enabled. * @retval WHAL_EINVAL Invalid arguments. - * @retval WHAL_ETIMEOUT Link did not come up. + * @retval WHAL_ETIMEOUT PHY reset did not complete. */ whal_Error whal_Lan8742a_Init(whal_EthPhy *phyDev); /* * @brief Deinitialize the LAN8742A PHY. * - * Powers down the PHY. + * Powers down the PHY (BMCR power-down bit). Init clears it again. * * @param phyDev PHY device instance. * @@ -84,6 +84,7 @@ whal_Error whal_Lan8742a_Deinit(whal_EthPhy *phyDev); * @param phyDev PHY device instance. * @param up Output: 1 if link is up, 0 if down. * @param speed Output: negotiated speed (10 or 100). + * @param duplex Output: 1 for full duplex, 0 for half duplex. * * @retval WHAL_SUCCESS Link state read. * @retval WHAL_EINVAL Invalid arguments. From a2accc5e043dfb0a38107ce22767d9ee1df42af0 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 12:59:13 -0400 Subject: [PATCH 07/18] [uart, dma, stm32wb, stm32wba, stm32f4, stm32l1, stm32u5, stm32n6] Fix DMA-UART zero-length and teardown, F4 TC wait, GPDMA REQSEL width - Widen GPDMA REQSEL to 8 bits so U5/N6 request IDs >= 64 are not truncated - DMA-UART: check busy before the zero-length shortcut so blocking calls never wait on or abort another transfer (WB, WBA) - DMA-UART: add Deinit that stops both DMA channels and resets transfer state (WB, WBA); keep the WBA 1-byte TX bounce per instance - F4/L1 UART Send waits for TC after the last byte - Fix F0 UART Send and DMA callback docs --- src/dma/stm32wba_gpdma.c | 2 +- src/uart/stm32f4_uart.c | 4 ++- src/uart/stm32wb_uart.c | 1 - src/uart/stm32wb_uart_dma.c | 48 ++++++++++++++++++++++++------ src/uart/stm32wba_uart_dma.c | 50 ++++++++++++++++++++++++-------- wolfHAL/dma/dma.h | 6 ++-- wolfHAL/dma/stm32wba_gpdma.h | 5 ++-- wolfHAL/uart/stm32f0_uart.h | 4 +-- wolfHAL/uart/stm32wb_uart.h | 5 ++++ wolfHAL/uart/stm32wb_uart_dma.h | 16 +++++++++- wolfHAL/uart/stm32wba_uart_dma.h | 19 ++++++++++-- 11 files changed, 126 insertions(+), 34 deletions(-) diff --git a/src/dma/stm32wba_gpdma.c b/src/dma/stm32wba_gpdma.c index 4012fea..cd75e07 100644 --- a/src/dma/stm32wba_gpdma.c +++ b/src/dma/stm32wba_gpdma.c @@ -122,7 +122,7 @@ /* CxTR2 bits */ #define GPDMA_CxTR2_REQSEL_Pos 0 /* Hardware request selection */ -#define GPDMA_CxTR2_REQSEL_Msk (0x3FUL << GPDMA_CxTR2_REQSEL_Pos) +#define GPDMA_CxTR2_REQSEL_Msk (0xFFUL << GPDMA_CxTR2_REQSEL_Pos) #define GPDMA_CxTR2_SWREQ_Pos 9 /* Software request (memory-to-memory) */ #define GPDMA_CxTR2_SWREQ_Msk (1UL << GPDMA_CxTR2_SWREQ_Pos) #define GPDMA_CxTR2_DREQ_Pos 10 /* Direction: 0=src periph, 1=dst periph */ diff --git a/src/uart/stm32f4_uart.c b/src/uart/stm32f4_uart.c index 2e37b49..17d6883 100644 --- a/src/uart/stm32f4_uart.c +++ b/src/uart/stm32f4_uart.c @@ -182,7 +182,9 @@ whal_Error whal_Stm32f4_Uart_Send(whal_Uart *uartDev, const void *data, size_t d whal_Reg_Write(base, UART_DR_REG, buf[i]); } - return WHAL_SUCCESS; + /* Wait for the last frame to finish shifting out */ + return whal_Reg_ReadPoll(base, UART_SR_REG, UART_SR_TC_Msk, + UART_SR_TC_Msk, cfg->timeout); } whal_Error whal_Stm32f4_Uart_Recv(whal_Uart *uartDev, void *data, size_t dataSz) diff --git a/src/uart/stm32wb_uart.c b/src/uart/stm32wb_uart.c index f0a5931..c43a946 100644 --- a/src/uart/stm32wb_uart.c +++ b/src/uart/stm32wb_uart.c @@ -76,7 +76,6 @@ #ifdef WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING #define whal_Stm32wb_Uart_Init whal_Uart_Init -#define whal_Stm32wb_Uart_Deinit whal_Uart_Deinit #endif /* WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING */ #ifdef WHAL_CFG_STM32WB_UART_SINGLE_INSTANCE diff --git a/src/uart/stm32wb_uart_dma.c b/src/uart/stm32wb_uart_dma.c index 43548d1..1189db9 100644 --- a/src/uart/stm32wb_uart_dma.c +++ b/src/uart/stm32wb_uart_dma.c @@ -49,10 +49,13 @@ #if defined(WHAL_CFG_STM32WB_UART_DIRECT_API_MAPPING) || \ defined(WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING) #define whal_Stm32wb_Uart_Init whal_Uart_Init +#endif +#ifdef WHAL_CFG_STM32WB_UART_DIRECT_API_MAPPING #define whal_Stm32wb_Uart_Deinit whal_Uart_Deinit #endif #ifdef WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING +#define whal_Stm32wb_UartDma_Deinit whal_Uart_Deinit #define whal_Stm32wb_UartDma_Send whal_Uart_Send #define whal_Stm32wb_UartDma_Recv whal_Uart_Recv #define whal_Stm32wb_UartDma_SendAsync whal_Uart_SendAsync @@ -86,12 +89,12 @@ whal_Error whal_Stm32wb_UartDma_SendAsync(whal_Uart *uartDev, const void *data, base = uartDev->base; #endif - if (dataSz == 0) - return WHAL_SUCCESS; - if (cfg->txResult == WHAL_ENOTREADY) return WHAL_ENOTREADY; + if (dataSz == 0) + return WHAL_SUCCESS; + cfg->txChCfg->srcAddr = (uint32_t)(uintptr_t)data; cfg->txChCfg->dstAddr = (uint32_t)(base + UART_TDR_REG); cfg->txChCfg->length = dataSz; @@ -140,12 +143,12 @@ whal_Error whal_Stm32wb_UartDma_RecvAsync(whal_Uart *uartDev, void *data, base = uartDev->base; #endif - if (dataSz == 0) - return WHAL_SUCCESS; - if (cfg->rxResult == WHAL_ENOTREADY) return WHAL_ENOTREADY; + if (dataSz == 0) + return WHAL_SUCCESS; + cfg->rxChCfg->srcAddr = (uint32_t)(base + UART_RDR_REG); cfg->rxChCfg->dstAddr = (uint32_t)(uintptr_t)data; cfg->rxChCfg->length = dataSz; @@ -179,7 +182,7 @@ whal_Error whal_Stm32wb_UartDma_Send(whal_Uart *uartDev, const void *data, whal_Error err; err = whal_Stm32wb_UartDma_SendAsync(uartDev, data, dataSz); - if (err) + if (err || dataSz == 0) return err; #ifdef WHAL_CFG_STM32WB_UART_DMA_SINGLE_INSTANCE @@ -222,7 +225,7 @@ whal_Error whal_Stm32wb_UartDma_Recv(whal_Uart *uartDev, void *data, whal_Error err; err = whal_Stm32wb_UartDma_RecvAsync(uartDev, data, dataSz); - if (err) + if (err || dataSz == 0) return err; #ifdef WHAL_CFG_STM32WB_UART_DMA_SINGLE_INSTANCE @@ -251,6 +254,33 @@ whal_Error whal_Stm32wb_UartDma_Recv(whal_Uart *uartDev, void *data, return err; } +whal_Error whal_Stm32wb_UartDma_Deinit(whal_Uart *uartDev) +{ + whal_Stm32wb_UartDma_Cfg *cfg; + size_t base; + +#ifdef WHAL_CFG_STM32WB_UART_DMA_SINGLE_INSTANCE + cfg = (whal_Stm32wb_UartDma_Cfg *)whal_Stm32wb_UartDma_Dev.cfg; + base = whal_Stm32wb_UartDma_Dev.base; +#else + if (!uartDev || !uartDev->cfg) + return WHAL_EINVAL; + + cfg = (whal_Stm32wb_UartDma_Cfg *)uartDev->cfg; + base = uartDev->base; +#endif + + /* Abandon any in-flight transfer so a later Init starts clean */ + whal_Reg_Update(base, UART_CR3_REG, + UART_CR3_DMAT_Msk | UART_CR3_DMAR_Msk, 0); + whal_Dma_Stop(cfg->dma, cfg->txCh); + whal_Dma_Stop(cfg->dma, cfg->rxCh); + cfg->txResult = WHAL_SUCCESS; + cfg->rxResult = WHAL_SUCCESS; + + return whal_Stm32wb_Uart_Deinit(uartDev); +} + void whal_Stm32wb_UartDma_TxCallback(void *ctx, whal_Error err) { whal_Stm32wb_UartDma_Cfg *cfg = (whal_Stm32wb_UartDma_Cfg *)ctx; @@ -266,7 +296,7 @@ void whal_Stm32wb_UartDma_RxCallback(void *ctx, whal_Error err) #ifndef WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING const whal_UartDriver whal_Stm32wb_UartDma_Driver = { .Init = whal_Stm32wb_Uart_Init, - .Deinit = whal_Stm32wb_Uart_Deinit, + .Deinit = whal_Stm32wb_UartDma_Deinit, .Send = whal_Stm32wb_UartDma_Send, .Recv = whal_Stm32wb_UartDma_Recv, .SendAsync = whal_Stm32wb_UartDma_SendAsync, diff --git a/src/uart/stm32wba_uart_dma.c b/src/uart/stm32wba_uart_dma.c index cc36c49..00f0a40 100644 --- a/src/uart/stm32wba_uart_dma.c +++ b/src/uart/stm32wba_uart_dma.c @@ -72,9 +72,6 @@ whal_Error whal_Stm32wba_UartDma_SendAsync(whal_Uart *uartDev, const void *data, return WHAL_EINVAL; #endif - if (dataSz == 0) - return WHAL_SUCCESS; - #ifndef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE cfg = (whal_Stm32wba_UartDma_Cfg *)uartDev->cfg; #endif @@ -82,15 +79,17 @@ whal_Error whal_Stm32wba_UartDma_SendAsync(whal_Uart *uartDev, const void *data, if (cfg->txResult == WHAL_ENOTREADY) return WHAL_ENOTREADY; + if (dataSz == 0) + return WHAL_SUCCESS; + #ifndef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE base = uartDev->base; #endif /* Single-byte DMA from flash fails on GPDMA — bounce through SRAM */ - static volatile uint8_t txBounce; if (dataSz == 1) { - txBounce = *(const uint8_t *)data; - cfg->txChCfg->srcAddr = (size_t)&txBounce; + cfg->txBounce = *(const uint8_t *)data; + cfg->txChCfg->srcAddr = (size_t)&cfg->txBounce; } else { cfg->txChCfg->srcAddr = (size_t)data; } @@ -139,9 +138,6 @@ whal_Error whal_Stm32wba_UartDma_RecvAsync(whal_Uart *uartDev, void *data, return WHAL_EINVAL; #endif - if (dataSz == 0) - return WHAL_SUCCESS; - #ifndef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE cfg = (whal_Stm32wba_UartDma_Cfg *)uartDev->cfg; #endif @@ -149,6 +145,9 @@ whal_Error whal_Stm32wba_UartDma_RecvAsync(whal_Uart *uartDev, void *data, if (cfg->rxResult == WHAL_ENOTREADY) return WHAL_ENOTREADY; + if (dataSz == 0) + return WHAL_SUCCESS; + #ifndef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE base = uartDev->base; #endif @@ -186,7 +185,7 @@ whal_Error whal_Stm32wba_UartDma_Send(whal_Uart *uartDev, const void *data, whal_Error err; err = whal_Stm32wba_UartDma_SendAsync(uartDev, data, dataSz); - if (err) + if (err || dataSz == 0) return err; #ifdef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE @@ -232,7 +231,7 @@ whal_Error whal_Stm32wba_UartDma_Recv(whal_Uart *uartDev, void *data, whal_Error err; err = whal_Stm32wba_UartDma_RecvAsync(uartDev, data, dataSz); - if (err) + if (err || dataSz == 0) return err; #ifdef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE @@ -261,6 +260,33 @@ whal_Error whal_Stm32wba_UartDma_Recv(whal_Uart *uartDev, void *data, return err; } +whal_Error whal_Stm32wba_UartDma_Deinit(whal_Uart *uartDev) +{ + whal_Stm32wba_UartDma_Cfg *cfg; + size_t base; + +#ifdef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE + cfg = (whal_Stm32wba_UartDma_Cfg *)whal_Stm32wba_UartDma_Dev.cfg; + base = whal_Stm32wba_UartDma_Dev.base; +#else + if (!uartDev || !uartDev->cfg) + return WHAL_EINVAL; + + cfg = (whal_Stm32wba_UartDma_Cfg *)uartDev->cfg; + base = uartDev->base; +#endif + + /* Abandon any in-flight transfer so a later Init starts clean */ + whal_Reg_Update(base, UART_CR3_REG, + UART_CR3_DMAT_Msk | UART_CR3_DMAR_Msk, 0); + whal_Dma_Stop(cfg->dma, cfg->txCh); + whal_Dma_Stop(cfg->dma, cfg->rxCh); + cfg->txResult = WHAL_SUCCESS; + cfg->rxResult = WHAL_SUCCESS; + + return whal_Stm32wb_Uart_Deinit(uartDev); +} + void whal_Stm32wba_UartDma_TxCallback(void *ctx, whal_Error err) { whal_Stm32wba_UartDma_Cfg *cfg = (whal_Stm32wba_UartDma_Cfg *)ctx; @@ -275,7 +301,7 @@ void whal_Stm32wba_UartDma_RxCallback(void *ctx, whal_Error err) const whal_UartDriver whal_Stm32wba_UartDma_Driver = { .Init = whal_Stm32wb_Uart_Init, - .Deinit = whal_Stm32wb_Uart_Deinit, + .Deinit = whal_Stm32wba_UartDma_Deinit, .Send = whal_Stm32wba_UartDma_Send, .Recv = whal_Stm32wba_UartDma_Recv, .SendAsync = whal_Stm32wba_UartDma_SendAsync, diff --git a/wolfHAL/dma/dma.h b/wolfHAL/dma/dma.h index 8d9751a..85fc288 100644 --- a/wolfHAL/dma/dma.h +++ b/wolfHAL/dma/dma.h @@ -36,12 +36,12 @@ * Typical usage from a peripheral driver: * 1. whal_Dma_Init() — enable the DMA controller * 2. whal_Dma_Configure() — set up a channel (direction, width, src/dst, - * buffer, length, callback, etc.) + * buffer, length, etc.) * 3. whal_Dma_Start() — kick off the transfer * 4. whal_Dma_Stop() — abort or clean up after completion * - * The completion callback (provided in the platform-specific channel config) - * runs in ISR context. + * Completion callbacks are passed by the board's IRQ handler to the platform + * DMA IRQ handler and run in ISR context. */ typedef struct whal_Dma whal_Dma; diff --git a/wolfHAL/dma/stm32wba_gpdma.h b/wolfHAL/dma/stm32wba_gpdma.h index b909f10..1a76c30 100644 --- a/wolfHAL/dma/stm32wba_gpdma.h +++ b/wolfHAL/dma/stm32wba_gpdma.h @@ -72,7 +72,8 @@ typedef enum { * @brief Per-channel transfer configuration. * * For hardware-paced transfers, reqSel selects the peripheral request line - * (REQSEL[5:0] from TRM Table 208 - e.g. 11=USART1_RX, 12=USART1_TX). + * (REQSEL from the RM request table - e.g. WBA 11=USART1_RX, 12=USART1_TX; + * the field is 6 bits on WBA, 7 on U5, 8 on N6). */ typedef struct { whal_Stm32wba_Gpdma_Dir dir; @@ -83,7 +84,7 @@ typedef struct { whal_Stm32wba_Gpdma_Width dstWidth; whal_Stm32wba_Gpdma_Inc srcInc; whal_Stm32wba_Gpdma_Inc dstInc; - uint8_t reqSel; /* REQSEL[5:0] (ignored for MEM_TO_MEM) */ + uint8_t reqSel; /* REQSEL (ignored for MEM_TO_MEM) */ } whal_Stm32wba_Gpdma_ChCfg; /* diff --git a/wolfHAL/uart/stm32f0_uart.h b/wolfHAL/uart/stm32f0_uart.h index eba9fba..cf7c205 100644 --- a/wolfHAL/uart/stm32f0_uart.h +++ b/wolfHAL/uart/stm32f0_uart.h @@ -78,7 +78,7 @@ whal_Error whal_Stm32f0_Uart_Init(whal_Uart *uartDev); whal_Error whal_Stm32f0_Uart_Deinit(whal_Uart *uartDev); /* - * @brief Send `dataSz` bytes from `data`, polling TXE between bytes. + * @brief Send `dataSz` bytes from `data`, polling TC after each byte. * * @param uartDev UART device instance. * @param data Buffer to send. @@ -86,7 +86,7 @@ whal_Error whal_Stm32f0_Uart_Deinit(whal_Uart *uartDev); * * @retval WHAL_SUCCESS All bytes sent. * @retval WHAL_EINVAL Null pointer. - * @retval WHAL_ETIMEOUT Hardware did not assert TXE within the configured timeout. + * @retval WHAL_ETIMEOUT Hardware did not assert TC within the configured timeout. */ whal_Error whal_Stm32f0_Uart_Send(whal_Uart *uartDev, const void *data, size_t dataSz); diff --git a/wolfHAL/uart/stm32wb_uart.h b/wolfHAL/uart/stm32wb_uart.h index f8bf63c..c9b92e4 100644 --- a/wolfHAL/uart/stm32wb_uart.h +++ b/wolfHAL/uart/stm32wb_uart.h @@ -121,4 +121,9 @@ whal_Error whal_Stm32wb_Uart_Send(whal_Uart *uartDev, const void *data, size_t d whal_Error whal_Stm32wb_Uart_Recv(whal_Uart *uartDev, void *data, size_t dataSz); #endif /* !WHAL_CFG_UART_API_MAPPING */ +#ifdef WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING +/* Polled Deinit, wrapped by the DMA-backed driver's Deinit. */ +whal_Error whal_Stm32wb_Uart_Deinit(whal_Uart *uartDev); +#endif + #endif /* WHAL_STM32WB_UART_H */ diff --git a/wolfHAL/uart/stm32wb_uart_dma.h b/wolfHAL/uart/stm32wb_uart_dma.h index fef48c7..8756686 100644 --- a/wolfHAL/uart/stm32wb_uart_dma.h +++ b/wolfHAL/uart/stm32wb_uart_dma.h @@ -36,7 +36,8 @@ /* * @brief DMA-backed UART configuration. * - * Used with whal_Stm32wb_UartDma_Driver. Init/Deinit reuse the polled driver. + * Used with whal_Stm32wb_UartDma_Driver. Init reuses the polled driver; + * Deinit also stops the DMA channels. * Send/Recv block using DMA. SendAsync/RecvAsync return immediately. */ typedef struct { @@ -65,6 +66,19 @@ extern const whal_Uart whal_Stm32wb_UartDma_Dev; */ extern const whal_UartDriver whal_Stm32wb_UartDma_Driver; +/* + * @brief Deinitialize the UART, stopping both DMA channels. + * + * Clears the UART DMA requests, stops the TX and RX channels, resets the + * transfer state, then deinitializes the UART. + * + * @param uartDev UART device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32wb_UartDma_Deinit(whal_Uart *uartDev); + /* * @brief Transmit a buffer over UART using DMA (blocking). * diff --git a/wolfHAL/uart/stm32wba_uart_dma.h b/wolfHAL/uart/stm32wba_uart_dma.h index bebba0e..fd5113d 100644 --- a/wolfHAL/uart/stm32wba_uart_dma.h +++ b/wolfHAL/uart/stm32wba_uart_dma.h @@ -33,8 +33,9 @@ * @brief STM32WBA UART driver -- GPDMA-backed variant. * * Uses the STM32WBA GPDMA controller to move bytes between memory and the - * USART TDR/RDR registers. Init/Deinit reuse the polled UART driver; Send/Recv - * block using DMA; SendAsync/RecvAsync return immediately. + * USART TDR/RDR registers. Init reuses the polled UART driver; Deinit also + * stops the DMA channels; Send/Recv block using DMA; SendAsync/RecvAsync + * return immediately. * * The GPDMA request lines for USART are (RM0493 Table 208): * REQSEL 11 = USART1_RX @@ -59,6 +60,7 @@ typedef struct { whal_Stm32wba_Gpdma_ChCfg *rxChCfg; /* RX channel cfg */ volatile whal_Error txResult; /* Set by TX completion callback */ volatile whal_Error rxResult; /* Set by RX completion callback */ + volatile uint8_t txBounce; /* SRAM copy for 1-byte TX */ } whal_Stm32wba_UartDma_Cfg; /* @@ -74,6 +76,19 @@ extern const whal_Uart whal_Stm32wba_UartDma_Dev; */ extern const whal_UartDriver whal_Stm32wba_UartDma_Driver; +/* + * @brief Deinitialize the UART, stopping both DMA channels. + * + * Clears the UART DMA requests, stops the TX and RX channels, resets the + * transfer state, then deinitializes the UART. + * + * @param uartDev UART device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32wba_UartDma_Deinit(whal_Uart *uartDev); + /* * @brief Send `dataSz` bytes via GPDMA. Blocks until the transfer completes. * From 506a155ad9584f09579eb2fa16b1fe2e57407b7c Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 13:28:53 -0400 Subject: [PATCH 08/18] [i2c, gpio, stm32wb, stm32l1, stm32wb0, spi, reg] Scale I2C timing to requested freq, fix L1 I2C recovery, bound GPIO index - I2C (WB family): derive SCL low/high from the requested frequency instead of only the speed mode; wait for TC before STOP or a repeated START - I2C (L1): reject NULL message buffers, clear ACK/POS and STOP on errors, software-reset a bus left busy before StartCom - GPIO (WB, WB0): reject pin indexes past the configured pin table; add an out-of-range index check to the GPIO test - Fix WB SPI frame-size, GPIO AFR and whal_Reg_Update docs --- src/gpio/stm32wb0_gpio.c | 5 +---- src/gpio/stm32wb_gpio.c | 13 +------------ src/i2c/stm32l1_i2c.c | 35 +++++++++++++++++++++++++++-------- src/i2c/stm32wb_i2c.c | 19 ++++++++++++++----- tests/gpio/test_gpio.c | 4 ++++ wolfHAL/reg.h | 3 ++- wolfHAL/spi/stm32wb_spi.h | 2 +- 7 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/gpio/stm32wb0_gpio.c b/src/gpio/stm32wb0_gpio.c index 7be8e43..88ea630 100644 --- a/src/gpio/stm32wb0_gpio.c +++ b/src/gpio/stm32wb0_gpio.c @@ -121,16 +121,13 @@ static whal_Error whal_Stm32wb0_Gpio_SetOrGet(whal_Gpio *gpioDev, size_t idx, size_t portBase, mask; (void)gpioDev; - if (!value) + if (!value || idx >= cfg->pinCount) return WHAL_EINVAL; pinCfg = cfg->pinCfg[idx]; port = WHAL_STM32WB0_GPIO_GET_PORT(pinCfg); pin = WHAL_STM32WB0_GPIO_GET_PIN(pinCfg); - if (pin > 15) - return WHAL_EINVAL; - portBase = whal_Stm32wb0_Gpio_Dev.base + (port * GPIO_PORT_STRIDE); mask = 1UL << pin; diff --git a/src/gpio/stm32wb_gpio.c b/src/gpio/stm32wb_gpio.c index 081e2ae..eb56c42 100644 --- a/src/gpio/stm32wb_gpio.c +++ b/src/gpio/stm32wb_gpio.c @@ -63,13 +63,6 @@ const whal_Gpio whal_Stm32wb_Gpio_Dev = WHAL_CFG_STM32WB_GPIO_DEV; #define whal_Stm32wb_Gpio_Set whal_Gpio_Set #endif /* WHAL_CFG_GPIO_API_MAPPING */ -/* - * Configure alternate function for a pin. - * - * The AFRL (pins 0-7) and AFRH (pins 8-15) registers are combined into - * a 64-bit value for easier manipulation. Each pin uses 4 bits to select - * one of 16 alternate functions (AF0-AF15). - */ /* * Initialize a single GPIO pin with the specified configuration. */ @@ -154,7 +147,7 @@ static whal_Error whal_Stm32wb_Gpio_SetOrGet(whal_Gpio *gpioDev, size_t idx, size_t portBase, mask; (void)gpioDev; - if (!value) { + if (!value || idx >= cfg->pinCount) { return WHAL_EINVAL; } @@ -162,10 +155,6 @@ static whal_Error whal_Stm32wb_Gpio_SetOrGet(whal_Gpio *gpioDev, size_t idx, port = WHAL_STM32WB_GPIO_GET_PORT(pinCfg); pin = WHAL_STM32WB_GPIO_GET_PIN(pinCfg); - if (pin > 15) { - return WHAL_EINVAL; - } - portBase = whal_Stm32wb_Gpio_Dev.base + (port * GPIO_PORT_SIZE); mask = 1UL << pin; diff --git a/src/i2c/stm32l1_i2c.c b/src/i2c/stm32l1_i2c.c index 6dacb8b..86dc2e3 100644 --- a/src/i2c/stm32l1_i2c.c +++ b/src/i2c/stm32l1_i2c.c @@ -86,6 +86,10 @@ #define SR1_ERR_Msk (SR1_BERR_Msk | SR1_ARLO_Msk | SR1_AF_Msk) +/* SR2 bits */ +#define SR2_BUSY_Pos 1 +#define SR2_BUSY_Msk (1UL << SR2_BUSY_Pos) + /* CCR bits */ #define CCR_CCR_Msk (WHAL_BITMASK(12)) #define CCR_FS_Pos 15 @@ -382,6 +386,13 @@ whal_Error whal_Stm32l1_I2c_StartCom(whal_I2c *i2cDev, whal_I2c_ComCfg *comCfg) base = i2cDev->base; #endif + /* A transfer abandoned on timeout can leave the bus marked busy; only a + * software reset clears that on the V1 peripheral */ + if (whal_Reg_Read(base, I2C_SR2) & SR2_BUSY_Msk) { + whal_Reg_Update(base, I2C_CR1, CR1_SWRST_Msk, CR1_SWRST_Msk); + whal_Reg_Update(base, I2C_CR1, CR1_SWRST_Msk, 0); + } + whal_Reg_Update(base, I2C_CR1, CR1_PE_Msk, 0); freqMhz = cfg->pclk / 1000000; @@ -443,6 +454,11 @@ whal_Error whal_Stm32l1_I2c_Transfer(whal_I2c *i2cDev, whal_I2c_Msg *msgs, base = i2cDev->base; #endif + for (size_t i = 0; i < numMsgs; i++) { + if (!msgs[i].data || msgs[i].dataSz == 0) + return WHAL_EINVAL; + } + for (size_t i = 0; i < numMsgs; i++) { uint8_t isRead = (msgs[i].flags & WHAL_I2C_MSG_READ) ? 1 : 0; uint8_t doStart = (msgs[i].flags & WHAL_I2C_MSG_START) ? 1 : 0; @@ -450,15 +466,12 @@ whal_Error whal_Stm32l1_I2c_Transfer(whal_I2c *i2cDev, whal_I2c_Msg *msgs, uint8_t *buf = (uint8_t *)msgs[i].data; size_t len = msgs[i].dataSz; - if (len == 0) - return WHAL_EINVAL; - - if (doStart) { + err = WHAL_SUCCESS; + if (doStart) err = Stm32l1_I2c_SendStart(base, cfg->_addr, cfg->_addrSz, isRead, cfg->timeout); - if (err) - return err; - } + if (err) + goto error; if (isRead) { err = Stm32l1_I2c_MasterRead(base, buf, len, doStop, cfg->timeout); @@ -471,10 +484,16 @@ whal_Error whal_Stm32l1_I2c_Transfer(whal_I2c *i2cDev, whal_I2c_Msg *msgs, } if (err) - return err; + goto error; } return WHAL_SUCCESS; + +error: + whal_Reg_Update(base, I2C_CR1, CR1_ACK_Msk | CR1_POS_Msk, 0); + if (err == WHAL_ETIMEOUT) + whal_Reg_Update(base, I2C_CR1, CR1_STOP_Msk, CR1_STOP_Msk); + return err; } #if !defined(WHAL_CFG_STM32L1_I2C_DIRECT_API_MAPPING) diff --git a/src/i2c/stm32wb_i2c.c b/src/i2c/stm32wb_i2c.c index b0fa5e5..e15c66e 100644 --- a/src/i2c/stm32wb_i2c.c +++ b/src/i2c/stm32wb_i2c.c @@ -159,27 +159,34 @@ const whal_I2c whal_Stm32wb_I2c_Dev = WHAL_CFG_STM32WB_I2C_DEV; static uint32_t Stm32wb_I2c_CalcTimingr(uint32_t pclk, uint32_t freq) { - uint32_t tLowNs, tHighNs; + uint32_t tLowNs, tHighNs, modeMax; uint32_t presc, scll, sclh, sdadel, scldel; uint32_t tPrescNs; if (freq <= 100000) { tLowNs = I2C_SM_TLOW_NS; tHighNs = I2C_SM_THIGH_NS; + modeMax = 100000; sdadel = 2; scldel = 4; } else if (freq <= 400000) { tLowNs = I2C_FM_TLOW_NS; tHighNs = I2C_FM_THIGH_NS; + modeMax = 400000; sdadel = 1; scldel = 3; } else { tLowNs = I2C_FMP_TLOW_NS; tHighNs = I2C_FMP_THIGH_NS; + modeMax = 1000000; sdadel = 0; scldel = 1; } + /* Stretch the mode's minimum low/high times to the requested frequency */ + tLowNs = tLowNs * modeMax / freq; + tHighNs = tHighNs * modeMax / freq; + for (presc = 0; presc < 16; presc++) { tPrescNs = ((presc + 1) * 1000) / (pclk / 1000000); if (tPrescNs == 0) @@ -328,8 +335,9 @@ static whal_Error Stm32wb_I2c_TransferChunk(size_t base, uint8_t *buf, * WHAL_I2C_MSG_READ — master read * WHAL_I2C_MSG_WRITE — master write * - * When STOP is not set, the function waits for TC (transfer complete) which - * stretches SCL low, holding the bus for the next message's START. + * Unless the last chunk uses RELOAD, the function waits for TC (transfer + * complete), which stretches SCL low and holds the bus for the STOP or the + * next message's repeated START. */ /* * @param reloadLast If true, use RELOAD on the last chunk so the next @@ -373,13 +381,14 @@ static whal_Error Stm32wb_I2c_TransferMsg(size_t base, whal_I2c_Msg *msg, if (err) return err; - if (doStop) { - /* Wait for TC, then issue STOP */ + if (!reloadLast) { err = Stm32wb_I2c_WaitFlag(base, I2C_ISR_TC_Msk, I2C_ISR_TC_Msk, timeout); if (err) return err; + } + if (doStop) { whal_Reg_Update(base, I2C_CR2_REG, I2C_CR2_STOP_Msk, whal_SetBits(I2C_CR2_STOP_Msk, I2C_CR2_STOP_Pos, 1)); diff --git a/tests/gpio/test_gpio.c b/tests/gpio/test_gpio.c index b620fc2..514b037 100644 --- a/tests/gpio/test_gpio.c +++ b/tests/gpio/test_gpio.c @@ -25,7 +25,11 @@ static void Test_Gpio_Api(void) { + size_t val; + WHAL_ASSERT_EQ(whal_Gpio_Get(BOARD_GPIO_DEV, 0, NULL), WHAL_EINVAL); + /* Index past the end of every board's pin table */ + WHAL_ASSERT_EQ(whal_Gpio_Get(BOARD_GPIO_DEV, 0xFFFF, &val), WHAL_EINVAL); } static void Test_Gpio_SetGetHighLow(void) diff --git a/wolfHAL/reg.h b/wolfHAL/reg.h index dd1fa53..607a3b5 100644 --- a/wolfHAL/reg.h +++ b/wolfHAL/reg.h @@ -41,7 +41,8 @@ * @param base Base address of the register block. * @param offset Byte offset from @p base to the register. * @param mask Bit mask selecting the field to update. - * @param value Value to write, which will be masked and shifted. + * @param value Value already positioned within @p mask; it is masked but + * not shifted. * * @note No return value. Callers are responsible for passing valid inputs. */ diff --git a/wolfHAL/spi/stm32wb_spi.h b/wolfHAL/spi/stm32wb_spi.h index 56d4575..1030061 100644 --- a/wolfHAL/spi/stm32wb_spi.h +++ b/wolfHAL/spi/stm32wb_spi.h @@ -36,7 +36,7 @@ * - Master and slave modes (this driver supports master only) * - Configurable clock polarity and phase (SPI modes 0-3) * - Programmable baud rate prescaler (fPCLK/2 to fPCLK/256) - * - 4 to 16-bit data frame (this driver uses 8-bit) + * - 4 to 16-bit data frames (frames wider than 8 bits use two buffer bytes) * - Software slave management (chip select via GPIO) */ From 086d506be955dac839b051f29f9b289ea6220964 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 13:43:05 -0400 Subject: [PATCH 09/18] [timer, watchdog, pwm, irq, systick, stm32wb, stm32f0] Fix SysTick reload and counter, WWDG lower bounds, LPTIM PWM limits - SysTick: program RELOAD with cyclesPerTick - 1 and range-check it; clear CVR in Init and implement Reset - WWDG (F0/F3, WB/WBA/U5/N6): reject counter or window below 0x40, which would reset the MCU immediately - LPTIM PWM: reject period < 2 and 0% / 100% duty, which the LPTIM cannot produce (ARR must exceed CMP); update the platform test - Fix NVIC NULL-priority and IWDG start-order docs --- src/pwm/stm32wb_lptim_pwm.c | 15 +++++++++------ src/timer/systick.c | 12 +++++++++++- src/watchdog/stm32f0_wwdg.c | 4 +++- src/watchdog/stm32wb_wwdg.c | 4 +++- tests/pwm/test_stm32wb_pwm.c | 29 +++++++++++++++++++++++++---- wolfHAL/irq/cortex_m4_nvic.h | 3 ++- wolfHAL/pwm/stm32wb_lptim_pwm.h | 8 +++++--- wolfHAL/timer/systick.h | 6 +++++- wolfHAL/watchdog/stm32wb_iwdg.h | 5 +++-- 9 files changed, 66 insertions(+), 20 deletions(-) diff --git a/src/pwm/stm32wb_lptim_pwm.c b/src/pwm/stm32wb_lptim_pwm.c index 9d589c7..2184cd7 100644 --- a/src/pwm/stm32wb_lptim_pwm.c +++ b/src/pwm/stm32wb_lptim_pwm.c @@ -121,14 +121,17 @@ whal_Error whal_Stm32wb_Lptim_Pwm_Start(whal_Pwm *dev, uint8_t channel, return WHAL_ENOTSUP; } - /* ARR = period - 1; output is high while CNT > CMP, so CMP = ARR - pulse (0 when full-on). */ - arr = channelCfg->periodCycles - 1; - if (channelCfg->pulseCycles >= channelCfg->periodCycles) { - cmp = 0; - } else { - cmp = arr - channelCfg->pulseCycles; + /* The output clears on the ARR match and ARR must exceed CMP, so 0% and + * 100% duty and periods below 2 cannot be produced. */ + if (channelCfg->periodCycles < 2 || channelCfg->pulseCycles == 0 || + channelCfg->pulseCycles == channelCfg->periodCycles) { + return WHAL_ENOTSUP; } + /* ARR = period - 1; output is high while CNT > CMP, so CMP = ARR - pulse. */ + arr = channelCfg->periodCycles - 1; + cmp = arr - channelCfg->pulseCycles; + /* Disable so CFGR/ARR/CMP are writable, then set this call's polarity via WAVPOL. */ whal_Reg_Write(base, LPTIM_CR_REG, 0); whal_Reg_Update(base, LPTIM_CFGR_REG, LPTIM_CFGR_WAVPOL_Msk, diff --git a/src/timer/systick.c b/src/timer/systick.c index 434045b..bcad63d 100644 --- a/src/timer/systick.c +++ b/src/timer/systick.c @@ -45,6 +45,8 @@ const whal_Timer whal_SysTick_Dev = WHAL_CFG_SYSTICK_DEV; #define SYSTICK_RVR_RELOAD_Pos 0 #define SYSTICK_RVR_RELOAD_Msk (WHAL_BITMASK(24) << SYSTICK_RVR_RELOAD_Pos) +#define SYSTICK_CVR_REG 0x08 + #ifdef WHAL_CFG_SYSTICK_TIMER_DIRECT_API_MAPPING #define whal_SysTick_Init whal_Timer_Init #define whal_SysTick_Deinit whal_Timer_Deinit @@ -60,6 +62,10 @@ whal_Error whal_SysTick_Init(whal_Timer *timerDev) size_t base = whal_SysTick_Dev.base; (void)timerDev; + /* RELOAD is 24 bits and holds the period minus one */ + if (cfg->cyclesPerTick == 0 || cfg->cyclesPerTick > 0x1000000) + return WHAL_EINVAL; + whal_Reg_Update(base, SYSTICK_CSR_REG, SYSTICK_CSR_CLKSOURCE_Msk | SYSTICK_CSR_TICKINT_Msk, whal_SetBits(SYSTICK_CSR_CLKSOURCE_Msk, SYSTICK_CSR_CLKSOURCE_Pos, cfg->clkSrc) | @@ -67,7 +73,10 @@ whal_Error whal_SysTick_Init(whal_Timer *timerDev) whal_Reg_Update(base, SYSTICK_RVR_REG, SYSTICK_RVR_RELOAD_Msk, - whal_SetBits(SYSTICK_RVR_RELOAD_Msk, SYSTICK_RVR_RELOAD_Pos, cfg->cyclesPerTick)); + whal_SetBits(SYSTICK_RVR_RELOAD_Msk, SYSTICK_RVR_RELOAD_Pos, cfg->cyclesPerTick - 1)); + + /* Any write clears the counter so the first period starts from RELOAD */ + whal_Reg_Write(base, SYSTICK_CVR_REG, 0); return WHAL_SUCCESS; } @@ -103,6 +112,7 @@ whal_Error whal_SysTick_Stop(whal_Timer *timerDev) whal_Error whal_SysTick_Reset(whal_Timer *timerDev) { (void)timerDev; + whal_Reg_Write(whal_SysTick_Dev.base, SYSTICK_CVR_REG, 0); return WHAL_SUCCESS; } diff --git a/src/watchdog/stm32f0_wwdg.c b/src/watchdog/stm32f0_wwdg.c index daf4658..2ff5be0 100644 --- a/src/watchdog/stm32f0_wwdg.c +++ b/src/watchdog/stm32f0_wwdg.c @@ -55,7 +55,9 @@ whal_Error whal_Stm32f0_Wwdg_Init(whal_Watchdog *wdgDev) size_t base = whal_Stm32f0_Wwdg_Dev.base; (void)wdgDev; - if (cfg->prescaler > 3 || cfg->window > 0x7F || cfg->counter > 0x7F) + /* Counter and window must keep T6 set or the MCU resets immediately */ + if (cfg->prescaler > 3 || cfg->window < 0x40 || cfg->window > 0x7F || + cfg->counter < 0x40 || cfg->counter > 0x7F) return WHAL_EINVAL; whal_Reg_Update(base, CFR_REG, CFR_W_Msk | CFR_WDGTB_Msk, diff --git a/src/watchdog/stm32wb_wwdg.c b/src/watchdog/stm32wb_wwdg.c index ad39b23..519c128 100644 --- a/src/watchdog/stm32wb_wwdg.c +++ b/src/watchdog/stm32wb_wwdg.c @@ -61,7 +61,9 @@ whal_Error whal_Stm32wb_Wwdg_Init(whal_Watchdog *wdgDev) size_t base = whal_Stm32wb_Wwdg_Dev.base; (void)wdgDev; - if (cfg->prescaler > 7 || cfg->window > 0x7F || cfg->counter > 0x7F) + /* Counter and window must keep T6 set or the MCU resets immediately */ + if (cfg->prescaler > 7 || cfg->window < 0x40 || cfg->window > 0x7F || + cfg->counter < 0x40 || cfg->counter > 0x7F) return WHAL_EINVAL; /* Configure window and prescaler */ diff --git a/tests/pwm/test_stm32wb_pwm.c b/tests/pwm/test_stm32wb_pwm.c index 8b1c2c9..bb68ea4 100644 --- a/tests/pwm/test_stm32wb_pwm.c +++ b/tests/pwm/test_stm32wb_pwm.c @@ -59,10 +59,24 @@ static void Test_Stm32wb_Lptim_Pwm_Reject(void) wave.pulseCount = 3; /* LPTIM has no pulse counter */ WHAL_ASSERT_EQ(whal_Stm32wb_Lptim_Pwm_Start(BOARD_PWM_DEV, WHAL_STM32WB_LPTIM_PWM_CHANNEL, &wave), WHAL_ENOTSUP); + wave.pulseCount = WHAL_PWM_PULSE_COUNT_CONTINUOUS; + + /* ARR must exceed CMP: 0% and 100% duty and periods below 2 */ + wave.pulseCycles = 0; + WHAL_ASSERT_EQ(whal_Stm32wb_Lptim_Pwm_Start(BOARD_PWM_DEV, + WHAL_STM32WB_LPTIM_PWM_CHANNEL, &wave), WHAL_ENOTSUP); + wave.pulseCycles = wave.periodCycles; + WHAL_ASSERT_EQ(whal_Stm32wb_Lptim_Pwm_Start(BOARD_PWM_DEV, + WHAL_STM32WB_LPTIM_PWM_CHANNEL, &wave), WHAL_ENOTSUP); + wave.periodCycles = 1; + wave.pulseCycles = 1; + WHAL_ASSERT_EQ(whal_Stm32wb_Lptim_Pwm_Start(BOARD_PWM_DEV, + WHAL_STM32WB_LPTIM_PWM_CHANNEL, &wave), WHAL_ENOTSUP); } -/* Accepted boundaries: the largest representable period and 100% duty. Each - * programs the LPTIM, so the channel is stopped again afterwards. */ +/* Accepted boundaries: the largest representable period and the highest and + * lowest representable duty. Each programs the LPTIM, so the channel is + * stopped again afterwards. */ static void Test_Stm32wb_Lptim_Pwm_Accept(void) { whal_Pwm_ChannelCfg wave = { @@ -78,9 +92,16 @@ static void Test_Stm32wb_Lptim_Pwm_Accept(void) WHAL_ASSERT_EQ(whal_Stm32wb_Lptim_Pwm_Stop(BOARD_PWM_DEV, WHAL_STM32WB_LPTIM_PWM_CHANNEL), WHAL_SUCCESS); - /* Maximum duty: pulse == period exercises the CMP = 0 branch. */ + /* Maximum duty: pulse == period - 1 gives CMP = 0. */ wave.periodCycles = 1000; - wave.pulseCycles = 1000; + wave.pulseCycles = 999; + WHAL_ASSERT_EQ(whal_Stm32wb_Lptim_Pwm_Start(BOARD_PWM_DEV, + WHAL_STM32WB_LPTIM_PWM_CHANNEL, &wave), WHAL_SUCCESS); + WHAL_ASSERT_EQ(whal_Stm32wb_Lptim_Pwm_Stop(BOARD_PWM_DEV, + WHAL_STM32WB_LPTIM_PWM_CHANNEL), WHAL_SUCCESS); + + /* Minimum duty: pulse == 1 gives CMP = ARR - 1. */ + wave.pulseCycles = 1; WHAL_ASSERT_EQ(whal_Stm32wb_Lptim_Pwm_Start(BOARD_PWM_DEV, WHAL_STM32WB_LPTIM_PWM_CHANNEL, &wave), WHAL_SUCCESS); WHAL_ASSERT_EQ(whal_Stm32wb_Lptim_Pwm_Stop(BOARD_PWM_DEV, diff --git a/wolfHAL/irq/cortex_m4_nvic.h b/wolfHAL/irq/cortex_m4_nvic.h index 09b24e2..fa7dc35 100644 --- a/wolfHAL/irq/cortex_m4_nvic.h +++ b/wolfHAL/irq/cortex_m4_nvic.h @@ -36,7 +36,8 @@ /* * @brief Optional per-interrupt configuration. * - * Pass to whal_Irq_Enable() to set priority, or pass NULL for default (0). + * Pass to whal_Irq_Enable() to set priority, or pass NULL to leave the + * current priority unchanged. */ typedef struct { uint8_t priority; diff --git a/wolfHAL/pwm/stm32wb_lptim_pwm.h b/wolfHAL/pwm/stm32wb_lptim_pwm.h index d770ef7..5186db7 100644 --- a/wolfHAL/pwm/stm32wb_lptim_pwm.h +++ b/wolfHAL/pwm/stm32wb_lptim_pwm.h @@ -112,7 +112,8 @@ whal_Error whal_Stm32wb_Lptim_Pwm_Deinit(whal_Pwm *dev); * * Because the LPTIM asserts its output while LPTIM_CNT exceeds LPTIM_CMP * (and clears it on the ARR match), the compare value is derived as - * (ARR - pulseCycles). + * (ARR - pulseCycles). ARR must exceed CMP, so pulseCycles must be between 1 + * and periodCycles - 1. * * @param dev Pointer to the PWM instance. * @param channel Must be WHAL_STM32WB_LPTIM_PWM_CHANNEL (0). @@ -121,8 +122,9 @@ whal_Error whal_Stm32wb_Lptim_Pwm_Deinit(whal_Pwm *dev); * @retval WHAL_SUCCESS Output started. * @retval WHAL_EINVAL Null pointer, missing configuration, zero period, or * pulse exceeding period. - * @retval WHAL_ENOTSUP Unsupported channel, period out of the 16-bit range, - * or a non-continuous pulse count. + * @retval WHAL_ENOTSUP Unsupported channel, period out of the 16-bit range or + * below 2, pulse of 0 or equal to the period, or a + * non-continuous pulse count. * @retval WHAL_ETIMEOUT ARR/CMP update did not synchronize before timeout. */ whal_Error whal_Stm32wb_Lptim_Pwm_Start(whal_Pwm *dev, uint8_t channel, diff --git a/wolfHAL/timer/systick.h b/wolfHAL/timer/systick.h index 2ab54de..bea0fa1 100644 --- a/wolfHAL/timer/systick.h +++ b/wolfHAL/timer/systick.h @@ -70,10 +70,12 @@ extern const whal_TimerDriver whal_SysTick_Driver; /* * @brief Initialize the SysTick timer with the configured clock and reload values. * + * Programs RELOAD with cyclesPerTick - 1 and clears the current counter. + * * @param timerDev Timer device instance to initialize. * * @retval WHAL_SUCCESS Initialization completed. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EINVAL cyclesPerTick is 0 or exceeds the 24-bit counter (2^24). */ whal_Error whal_SysTick_Init(whal_Timer *timerDev); /* @@ -106,6 +108,8 @@ whal_Error whal_SysTick_Stop(whal_Timer *timerDev); /* * @brief Reset the SysTick counter state. * + * Clears the current counter value so the next period starts from RELOAD. + * * @param timerDev Timer device instance. * * @retval WHAL_SUCCESS Timer reset. diff --git a/wolfHAL/watchdog/stm32wb_iwdg.h b/wolfHAL/watchdog/stm32wb_iwdg.h index c6e7311..86f21dc 100644 --- a/wolfHAL/watchdog/stm32wb_iwdg.h +++ b/wolfHAL/watchdog/stm32wb_iwdg.h @@ -72,8 +72,9 @@ extern const whal_WatchdogDriver whal_Stm32wb_Iwdg_Driver; /* * @brief Configure and start the STM32WB IWDG. * - * Sets the prescaler and reload value, then starts the watchdog. - * Once started, the IWDG cannot be stopped. + * Starts the IWDG, unlocks the prescaler and reload registers, programs them, + * waits for the update to complete, then reloads the counter. Once started, + * the IWDG cannot be stopped. * * @param wdgDev Watchdog device instance. * From 244b92174508de7e6dc1e6e300dee32fcc365f7b Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 14:35:42 -0400 Subject: [PATCH 10/18] [rng, stm32wb, stm32wba, stm32u5, stm32n6, stm32h5, stm32wb0] Check latched RNG errors, program WBA HTCR, check WB0 FAULT - Fail Generate on the latched SEIS flag, not just SECS (WB, WBA/U5/N6, H5); WB runs the RM0434 seed-error recovery, the others clear SEIS as required with auto-reset enabled - WBA/U5/N6: program RNG_HTCR with the Configuration C value during CONDRST - WB0: return EHARDWARE when RNG_SR.FAULT reports a bad noise sequence - Fix WB, WBA and WB0 RNG return-value docs --- src/rng/stm32h5_rng.c | 8 +++++++- src/rng/stm32wb0_rng.c | 6 ++++++ src/rng/stm32wb_rng.c | 11 +++++++++-- src/rng/stm32wba_rng.c | 18 +++++++++++++++++- wolfHAL/rng/stm32wb0_rng.h | 5 +++-- wolfHAL/rng/stm32wb_rng.h | 9 +++++---- wolfHAL/rng/stm32wba_rng.h | 3 --- 7 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/rng/stm32h5_rng.c b/src/rng/stm32h5_rng.c index f092218..162e668 100644 --- a/src/rng/stm32h5_rng.c +++ b/src/rng/stm32h5_rng.c @@ -63,6 +63,9 @@ const whal_Rng whal_Stm32h5_Rng_Dev = WHAL_CFG_STM32H5_RNG_DEV; #define RNG_SR_SECS_Pos 2 #define RNG_SR_SECS_Msk (1UL << RNG_SR_SECS_Pos) +#define RNG_SR_SEIS_Pos 6 +#define RNG_SR_SEIS_Msk (1UL << RNG_SR_SEIS_Pos) + /* Data Register - 32-bit random value */ #define RNG_DR_REG 0x08 @@ -156,7 +159,10 @@ whal_Error whal_Stm32h5_Rng_Generate(whal_Rng *rngDev, void *rngData, sr = whal_Reg_Read(base, RNG_SR_REG); - if (sr & RNG_SR_SECS_Msk) { + /* With auto-reset enabled SECS clears on its own; SEIS latches + * the error so the value around it is never returned */ + if (sr & (RNG_SR_SECS_Msk | RNG_SR_SEIS_Msk)) { + whal_Reg_Update(base, RNG_SR_REG, RNG_SR_SEIS_Msk, 0); err = WHAL_EHARDWARE; goto exit; } diff --git a/src/rng/stm32wb0_rng.c b/src/rng/stm32wb0_rng.c index 0a70f6d..e5ddc26 100644 --- a/src/rng/stm32wb0_rng.c +++ b/src/rng/stm32wb0_rng.c @@ -108,6 +108,12 @@ whal_Error whal_Stm32wb0_Rng_Generate(whal_Rng *rngDev, void *rngData, } } + /* FAULT latches a bad bit sequence from the noise source; write 1 to clear */ + if (whal_Reg_Read(base, RNG_SR_REG) & RNG_SR_FAULT_Msk) { + whal_Reg_Write(base, RNG_SR_REG, RNG_SR_FAULT_Msk); + return WHAL_EHARDWARE; + } + return WHAL_SUCCESS; } diff --git a/src/rng/stm32wb_rng.c b/src/rng/stm32wb_rng.c index 3b1f881..c404459 100644 --- a/src/rng/stm32wb_rng.c +++ b/src/rng/stm32wb_rng.c @@ -117,9 +117,9 @@ whal_Error whal_Stm32wb_Rng_Generate(whal_Rng *rngDev, void *rngData, size_t rng sr = whal_Reg_Read(base, RNG_SR_REG); /* Check for seed or clock error */ - if (sr & RNG_SR_SECS_Msk) { + if (sr & (RNG_SR_SECS_Msk | RNG_SR_SEIS_Msk)) { err = WHAL_EHARDWARE; - goto exit; + goto seed_error; } if (sr & RNG_SR_CECS_Msk) { err = WHAL_EHARDWARE; @@ -138,6 +138,13 @@ whal_Error whal_Stm32wb_Rng_Generate(whal_Rng *rngDev, void *rngData, size_t rng rngBuf[offset] = (uint8_t)(rnd >> (i * 8)); } } + goto exit; + +seed_error: + /* Seed error recovery (RM0434 21.3.7): clear SEIS, then discard 12 words */ + whal_Reg_Update(base, RNG_SR_REG, RNG_SR_SEIS_Msk, 0); + for (size_t i = 0; i < 12; i++) + (void)whal_Reg_Read(base, RNG_DR_REG); exit: /* Disable the RNG peripheral */ diff --git a/src/rng/stm32wba_rng.c b/src/rng/stm32wba_rng.c index cd9ad50..9ad6706 100644 --- a/src/rng/stm32wba_rng.c +++ b/src/rng/stm32wba_rng.c @@ -74,6 +74,15 @@ const whal_Rng whal_Stm32wba_Rng_Dev = WHAL_CFG_STM32WBA_RNG_DEV; /* Data Register (offset 0x008) */ #define RNG_DR_REG 0x08 +/* Health Test Control Register (offset 0x010) */ +#define RNG_HTCR_REG 0x10 + +/* Configuration C health test value (RM0493 Table 178; same on U5 and N6) */ +#define RNG_HTCR_CONFIG_C 0x0000AAC7UL + +/* Magic value written before HTCR (ST HAL, AN4230) */ +#define RNG_HTCR_MAGIC 0x17590ABCUL + /* * Configuration C values (RM0493 Table 178): * NISTC=0, RNG_CONFIG1=0x0F, CLKDIV=0x0, RNG_CONFIG2=0x0, @@ -99,6 +108,10 @@ whal_Error whal_Stm32wba_Rng_Init(whal_Rng *rngDev) whal_Reg_Write(base, RNG_CR_REG, RNG_CR_CONDRST_Msk | RNG_CR_CONFIG_C | RNG_CR_RNGEN_Msk); + /* HTCR only takes effect while CONDRST is set */ + whal_Reg_Write(base, RNG_HTCR_REG, RNG_HTCR_MAGIC); + whal_Reg_Write(base, RNG_HTCR_REG, RNG_HTCR_CONFIG_C); + /* Clear CONDRST to start conditioning */ whal_Reg_Write(base, RNG_CR_REG, RNG_CR_CONFIG_C | RNG_CR_RNGEN_Msk); @@ -145,7 +158,10 @@ whal_Error whal_Stm32wba_Rng_Generate(whal_Rng *rngDev, void *rngData, size_t rn sr = whal_Reg_Read(base, RNG_SR_REG); - if (sr & RNG_SR_SECS_Msk) { + /* With auto-reset enabled SECS clears on its own; SEIS latches + * the error so the value around it is never returned */ + if (sr & (RNG_SR_SECS_Msk | RNG_SR_SEIS_Msk)) { + whal_Reg_Update(base, RNG_SR_REG, RNG_SR_SEIS_Msk, 0); err = WHAL_EHARDWARE; goto exit; } diff --git a/wolfHAL/rng/stm32wb0_rng.h b/wolfHAL/rng/stm32wb0_rng.h index 5cc7557..0bbcb1e 100644 --- a/wolfHAL/rng/stm32wb0_rng.h +++ b/wolfHAL/rng/stm32wb0_rng.h @@ -92,8 +92,9 @@ whal_Error whal_Stm32wb0_Rng_Deinit(whal_Rng *rngDev); * @param rngData Destination buffer. * @param rngDataSz Number of random bytes to generate. * - * @retval WHAL_SUCCESS Buffer filled with random data. - * @retval WHAL_EINVAL Null destination buffer. + * @retval WHAL_SUCCESS Buffer filled with random data. + * @retval WHAL_EINVAL Null destination buffer. + * @retval WHAL_EHARDWARE RNG_SR.FAULT reported a faulty noise-source sequence. */ whal_Error whal_Stm32wb0_Rng_Generate(whal_Rng *rngDev, void *rngData, size_t rngDataSz); diff --git a/wolfHAL/rng/stm32wb_rng.h b/wolfHAL/rng/stm32wb_rng.h index 8e0ad57..8f5f51a 100644 --- a/wolfHAL/rng/stm32wb_rng.h +++ b/wolfHAL/rng/stm32wb_rng.h @@ -60,7 +60,6 @@ extern const whal_RngDriver whal_Stm32wb_Rng_Driver; * @param rngDev RNG device instance. * * @retval WHAL_SUCCESS Initialization completed. - * @retval WHAL_EINVAL Invalid arguments. */ whal_Error whal_Stm32wb_Rng_Init(whal_Rng *rngDev); /* @@ -69,7 +68,6 @@ whal_Error whal_Stm32wb_Rng_Init(whal_Rng *rngDev); * @param rngDev RNG device instance. * * @retval WHAL_SUCCESS Deinit completed. - * @retval WHAL_EINVAL Invalid arguments. */ whal_Error whal_Stm32wb_Rng_Deinit(whal_Rng *rngDev); /* @@ -79,8 +77,11 @@ whal_Error whal_Stm32wb_Rng_Deinit(whal_Rng *rngDev); * @param rngData Destination buffer. * @param rngDataSz Number of random bytes to generate. * - * @retval WHAL_SUCCESS Buffer filled with random data. - * @retval WHAL_EINVAL Invalid arguments or seed/clock error detected. + * @retval WHAL_SUCCESS Buffer filled with random data. + * @retval WHAL_EINVAL Null destination buffer. + * @retval WHAL_EHARDWARE Seed or clock error detected; after a seed error the + * driver runs the RM recovery so the next call can succeed. + * @retval WHAL_ETIMEOUT DRDY not set within the configured timeout. */ whal_Error whal_Stm32wb_Rng_Generate(whal_Rng *rngDev, void *rngData, size_t rngDataSz); #endif /* !WHAL_CFG_STM32WB_RNG_DIRECT_API_MAPPING */ diff --git a/wolfHAL/rng/stm32wba_rng.h b/wolfHAL/rng/stm32wba_rng.h index ed24dba..99c80ab 100644 --- a/wolfHAL/rng/stm32wba_rng.h +++ b/wolfHAL/rng/stm32wba_rng.h @@ -59,9 +59,7 @@ extern const whal_RngDriver whal_Stm32wba_Rng_Driver; * @param rngDev RNG device instance. * * @retval WHAL_SUCCESS RNG is ready. - * @retval WHAL_EINVAL Null pointer. * @retval WHAL_ETIMEOUT CONDRST did not complete within the configured timeout. - * @retval WHAL_EHARDWARE Health check or seed error reported. */ whal_Error whal_Stm32wba_Rng_Init(whal_Rng *rngDev); @@ -71,7 +69,6 @@ whal_Error whal_Stm32wba_Rng_Init(whal_Rng *rngDev); * @param rngDev RNG device instance. * * @retval WHAL_SUCCESS RNG disabled. - * @retval WHAL_EINVAL Null pointer. */ whal_Error whal_Stm32wba_Rng_Deinit(whal_Rng *rngDev); From e6acddb25dfb1122645f49ca9e136c635d2049bc Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 15:51:50 -0400 Subject: [PATCH 11/18] [flash, block, spi_nor, sdhc_spi] Bound SPI-NOR 3-byte ranges, preserve SR1 on lock, report SD stop errors - SPI-NOR 3-byte commands reject ranges that would cross 16 MB - SPI-NOR Lock/Unlock change only the block-protect bits, keeping the other SR1 bits (SRP0, TB/SEC, QE) - SD multi-block Read/Write return stop-sequence failures - SD CsAssert releases CS when its dummy byte fails --- src/block/sdhc_spi_block.c | 35 +++++++++++++++++++++++-------- src/flash/spi_nor_flash.c | 42 +++++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/src/block/sdhc_spi_block.c b/src/block/sdhc_spi_block.c index 58c97dd..b30274e 100644 --- a/src/block/sdhc_spi_block.c +++ b/src/block/sdhc_spi_block.c @@ -82,7 +82,10 @@ static whal_Error SdhcSpi_CsAssert(whal_SdhcSpi_Cfg *cfg) return err; /* Dummy byte gives card time to recognize CS transition */ - return whal_Spi_SendRecv(cfg->spiDev, &dummy, 1, NULL, 0); + err = whal_Spi_SendRecv(cfg->spiDev, &dummy, 1, NULL, 0); + if (err) + whal_Gpio_Set(cfg->gpioDev, cfg->csPin, 1); + return err; } static whal_Error SdhcSpi_CsDeassert(whal_SdhcSpi_Cfg *cfg) @@ -378,12 +381,20 @@ whal_Error whal_SdhcSpi_Read(whal_Block *blockDev, uint32_t block, break; } - /* Stop multi-block read */ + /* Stop multi-block read. A stuff byte can precede R1 after CMD12, so + * only transport errors and the busy wait are reported. */ if (blockCount > 1) { - SdhcSpi_SendCmd(cfg, CMD12, 0x00000000, 0x01); - SdhcSpi_RecvResp(cfg, &r1); - whal_Spi_SendRecv(cfg->spiDev, &dummy, 1, NULL, 0); - SdhcSpi_WaitReady(cfg); + whal_Error stopErr; + + stopErr = SdhcSpi_SendCmd(cfg, CMD12, 0x00000000, 0x01); + if (!stopErr) + stopErr = SdhcSpi_RecvResp(cfg, &r1); + if (!stopErr) + stopErr = whal_Spi_SendRecv(cfg->spiDev, &dummy, 1, NULL, 0); + if (!stopErr) + stopErr = SdhcSpi_WaitReady(cfg); + if (!err) + err = stopErr; } cleanup: @@ -468,10 +479,16 @@ whal_Error whal_SdhcSpi_Write(whal_Block *blockDev, uint32_t block, /* Stop multi-block write */ if (blockCount > 1) { + whal_Error stopErr; + token = TOKEN_STOP_TRAN; - whal_Spi_SendRecv(cfg->spiDev, &token, 1, NULL, 0); - whal_Spi_SendRecv(cfg->spiDev, &dummy, 1, NULL, 0); - SdhcSpi_WaitReady(cfg); + stopErr = whal_Spi_SendRecv(cfg->spiDev, &token, 1, NULL, 0); + if (!stopErr) + stopErr = whal_Spi_SendRecv(cfg->spiDev, &dummy, 1, NULL, 0); + if (!stopErr) + stopErr = SdhcSpi_WaitReady(cfg); + if (!err) + err = stopErr; } cleanup: diff --git a/src/flash/spi_nor_flash.c b/src/flash/spi_nor_flash.c index afbfb03..8df7aeb 100644 --- a/src/flash/spi_nor_flash.c +++ b/src/flash/spi_nor_flash.c @@ -256,6 +256,7 @@ whal_Error whal_SpiNor_Lock(whal_Flash *flashDev, size_t addr, size_t len) { whal_SpiNor_Cfg *cfg; uint8_t frame[2]; + uint8_t sr; whal_Error err; (void)addr; @@ -279,13 +280,17 @@ whal_Error whal_SpiNor_Lock(whal_Flash *flashDev, size_t addr, size_t len) if (err) goto cleanup; - /* Set all block protect bits to lock entire device */ + /* Lock the entire device: set all block protect bits, keep the other SR1 bits */ + err = SpiNor_ReadSR1(cfg, &sr); + if (err) + goto cleanup; + err = SpiNor_WriteEnable(cfg); if (err) goto cleanup; frame[0] = CMD_WRITE_SR; - frame[1] = SR1_BP_MASK; + frame[1] = (sr & ~(SR1_WIP | SR1_WEL)) | SR1_BP_MASK; err = SpiNor_CsAssert(cfg); if (err) goto cleanup; @@ -303,6 +308,7 @@ whal_Error whal_SpiNor_Unlock(whal_Flash *flashDev, size_t addr, size_t len) { whal_SpiNor_Cfg *cfg; uint8_t frame[2]; + uint8_t sr; whal_Error err; (void)addr; @@ -326,13 +332,17 @@ whal_Error whal_SpiNor_Unlock(whal_Flash *flashDev, size_t addr, size_t len) if (err) goto cleanup; - /* Clear all block protect bits to unlock entire device */ + /* Unlock the entire device: clear the block protect bits, keep the other SR1 bits */ + err = SpiNor_ReadSR1(cfg, &sr); + if (err) + goto cleanup; + err = SpiNor_WriteEnable(cfg); if (err) goto cleanup; frame[0] = CMD_WRITE_SR; - frame[1] = 0x00; + frame[1] = sr & ~(SR1_WIP | SR1_WEL | SR1_BP_MASK); err = SpiNor_CsAssert(cfg); if (err) goto cleanup; @@ -367,8 +377,8 @@ whal_Error whal_SpiNor3b_Read(whal_Flash *flashDev, size_t addr, void *data, cfg = (whal_SpiNor_Cfg *)flashDev->cfg; #endif - if (addr & ~0xFFFFFF || addr >= cfg->capacity || - dataSz > cfg->capacity - addr) + if (addr & ~0xFFFFFF || dataSz > 0x1000000 - addr || + addr >= cfg->capacity || dataSz > cfg->capacity - addr) return WHAL_EINVAL; err = whal_Spi_StartCom(cfg->spiDev, cfg->spiComCfg); @@ -417,8 +427,8 @@ whal_Error whal_SpiNor3b_Write(whal_Flash *flashDev, size_t addr, cfg = (whal_SpiNor_Cfg *)flashDev->cfg; #endif - if (addr & ~0xFFFFFF || addr >= cfg->capacity || - dataSz > cfg->capacity - addr) + if (addr & ~0xFFFFFF || dataSz > 0x1000000 - addr || + addr >= cfg->capacity || dataSz > cfg->capacity - addr) return WHAL_EINVAL; err = whal_Spi_StartCom(cfg->spiDev, cfg->spiComCfg); @@ -489,8 +499,8 @@ whal_Error whal_SpiNor3b_Erase4k(whal_Flash *flashDev, size_t addr, cfg = (whal_SpiNor_Cfg *)flashDev->cfg; #endif - if (addr & ~0xFFFFFF || addr >= cfg->capacity || - dataSz > cfg->capacity - addr) + if (addr & ~0xFFFFFF || dataSz > 0x1000000 - addr || + addr >= cfg->capacity || dataSz > cfg->capacity - addr) return WHAL_EINVAL; if ((addr | dataSz) & (ERASE_SZ_4K - 1)) @@ -553,8 +563,8 @@ whal_Error whal_SpiNor3b_Erase32k(whal_Flash *flashDev, size_t addr, cfg = (whal_SpiNor_Cfg *)flashDev->cfg; #endif - if (addr & ~0xFFFFFF || addr >= cfg->capacity || - dataSz > cfg->capacity - addr) + if (addr & ~0xFFFFFF || dataSz > 0x1000000 - addr || + addr >= cfg->capacity || dataSz > cfg->capacity - addr) return WHAL_EINVAL; if ((addr | dataSz) & (ERASE_SZ_32K - 1)) @@ -617,8 +627,8 @@ whal_Error whal_SpiNor3b_Erase64k(whal_Flash *flashDev, size_t addr, cfg = (whal_SpiNor_Cfg *)flashDev->cfg; #endif - if (addr & ~0xFFFFFF || addr >= cfg->capacity || - dataSz > cfg->capacity - addr) + if (addr & ~0xFFFFFF || dataSz > 0x1000000 - addr || + addr >= cfg->capacity || dataSz > cfg->capacity - addr) return WHAL_EINVAL; if ((addr | dataSz) & (ERASE_SZ_64K - 1)) @@ -717,8 +727,8 @@ whal_Error whal_SpiNor3b_ReadFast(whal_Flash *flashDev, size_t addr, cfg = (whal_SpiNor_Cfg *)flashDev->cfg; #endif - if (addr & ~0xFFFFFF || addr >= cfg->capacity || - dataSz > cfg->capacity - addr) + if (addr & ~0xFFFFFF || dataSz > 0x1000000 - addr || + addr >= cfg->capacity || dataSz > cfg->capacity - addr) return WHAL_EINVAL; err = whal_Spi_StartCom(cfg->spiDev, cfg->spiComCfg); From 72d3ba80111552d27ca137e2a327999eb7b467ee Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 16:03:53 -0400 Subject: [PATCH 12/18] [spi, watchdog, uart, stm32wba, stm32n6] Forward direct-mapping flags in WBA SPI, N6 WWDG and WBA UART-DMA - WBA SPI and N6 WWDG stubs forward their DIRECT_API_MAPPING flags to the reused driver, like their sibling stubs - WBA UART-DMA maps its functions to the generic whal_Uart_* names and hides the vtable under WHAL_CFG_STM32WBA_UART_DMA_DIRECT_API_MAPPING --- src/spi/stm32wba_spi.c | 3 +++ src/uart/stm32wba_uart_dma.c | 10 ++++++++++ src/watchdog/stm32n6_wwdg.c | 3 +++ wolfHAL/uart/stm32wba_uart_dma.h | 2 ++ 4 files changed, 18 insertions(+) diff --git a/src/spi/stm32wba_spi.c b/src/spi/stm32wba_spi.c index a8386ff..fc837cb 100644 --- a/src/spi/stm32wba_spi.c +++ b/src/spi/stm32wba_spi.c @@ -19,6 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#ifdef WHAL_CFG_STM32WBA_SPI_DIRECT_API_MAPPING +#define WHAL_CFG_STM32H5_SPI_DIRECT_API_MAPPING +#endif #ifdef WHAL_CFG_STM32WBA_SPI_SINGLE_INSTANCE #define WHAL_CFG_STM32H5_SPI_SINGLE_INSTANCE #endif diff --git a/src/uart/stm32wba_uart_dma.c b/src/uart/stm32wba_uart_dma.c index 00f0a40..c5f402a 100644 --- a/src/uart/stm32wba_uart_dma.c +++ b/src/uart/stm32wba_uart_dma.c @@ -48,6 +48,14 @@ #define UART_RDR_REG 0x24 #define UART_TDR_REG 0x28 +#ifdef WHAL_CFG_STM32WBA_UART_DMA_DIRECT_API_MAPPING +#define whal_Stm32wba_UartDma_Deinit whal_Uart_Deinit +#define whal_Stm32wba_UartDma_Send whal_Uart_Send +#define whal_Stm32wba_UartDma_Recv whal_Uart_Recv +#define whal_Stm32wba_UartDma_SendAsync whal_Uart_SendAsync +#define whal_Stm32wba_UartDma_RecvAsync whal_Uart_RecvAsync +#endif /* WHAL_CFG_STM32WBA_UART_DMA_DIRECT_API_MAPPING */ + #ifdef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE const whal_Uart whal_Stm32wba_UartDma_Dev = WHAL_CFG_STM32WBA_UART_DMA_DEV; #endif @@ -299,6 +307,7 @@ void whal_Stm32wba_UartDma_RxCallback(void *ctx, whal_Error err) cfg->rxResult = err; } +#ifndef WHAL_CFG_STM32WBA_UART_DMA_DIRECT_API_MAPPING const whal_UartDriver whal_Stm32wba_UartDma_Driver = { .Init = whal_Stm32wb_Uart_Init, .Deinit = whal_Stm32wba_UartDma_Deinit, @@ -307,3 +316,4 @@ const whal_UartDriver whal_Stm32wba_UartDma_Driver = { .SendAsync = whal_Stm32wba_UartDma_SendAsync, .RecvAsync = whal_Stm32wba_UartDma_RecvAsync, }; +#endif /* !WHAL_CFG_STM32WBA_UART_DMA_DIRECT_API_MAPPING */ diff --git a/src/watchdog/stm32n6_wwdg.c b/src/watchdog/stm32n6_wwdg.c index affae7c..27927b3 100644 --- a/src/watchdog/stm32n6_wwdg.c +++ b/src/watchdog/stm32n6_wwdg.c @@ -19,4 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#ifdef WHAL_CFG_STM32N6_WWDG_DIRECT_API_MAPPING +#define WHAL_CFG_STM32WB_WWDG_DIRECT_API_MAPPING +#endif #include "stm32wb_wwdg.c" diff --git a/wolfHAL/uart/stm32wba_uart_dma.h b/wolfHAL/uart/stm32wba_uart_dma.h index fd5113d..69b8869 100644 --- a/wolfHAL/uart/stm32wba_uart_dma.h +++ b/wolfHAL/uart/stm32wba_uart_dma.h @@ -71,6 +71,7 @@ typedef struct { extern const whal_Uart whal_Stm32wba_UartDma_Dev; #endif +#ifndef WHAL_CFG_STM32WBA_UART_DMA_DIRECT_API_MAPPING /* * @brief Driver instance for the GPDMA-backed STM32WBA UART. */ @@ -148,6 +149,7 @@ whal_Error whal_Stm32wba_UartDma_SendAsync(whal_Uart *uartDev, const void *data, */ whal_Error whal_Stm32wba_UartDma_RecvAsync(whal_Uart *uartDev, void *data, size_t dataSz); +#endif /* !WHAL_CFG_STM32WBA_UART_DMA_DIRECT_API_MAPPING */ /* * @brief GPDMA TX channel completion callback. Boards wire this into the From 3797ed9ad0ab5652a7d24b4bc9e7358bf953a575 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 6 Oct 2026 18:04:54 -0400 Subject: [PATCH 13/18] [crypto, aes, cryp, hash, stm32wb, stm32wba, stm32u5, stm32n6] CCM long AAD and length checks, streaming chunk and binding checks, dispatch and doc fixes - CCM: encode AAD lengths >= 0xFF00 as 0xFFFE + 4 bytes; reject payloads whose length does not fit in B0 (WB, WBA/U5, N6) - Streaming CCM: bind Start's tag length and payload length to Process and Finalize; GCM/CCM: reject Process after a partial block - Crypto dispatchers return EINVAL for a NULL device - WBA HASH Oneshot validates input before touching the core - Document CTR multiple-of-16 lengths, exact digest sizes, HMAC key lifetime and per-algorithm operations --- src/crypto/aes_cbc.c | 12 ++++-- src/crypto/aes_ccm.c | 16 ++++++-- src/crypto/aes_ctr.c | 12 ++++-- src/crypto/aes_ecb.c | 12 ++++-- src/crypto/aes_gcm.c | 16 ++++++-- src/crypto/aes_gmac.c | 4 +- src/crypto/hmac_sha1.c | 16 ++++++-- src/crypto/hmac_sha224.c | 16 ++++++-- src/crypto/hmac_sha256.c | 16 ++++++-- src/crypto/sha1.c | 16 ++++++-- src/crypto/sha224.c | 16 ++++++-- src/crypto/sha256.c | 16 ++++++-- src/crypto/stm32n6_cryp.c | 69 +++++++++++++++++++++++++++++++---- src/crypto/stm32wb_aes.c | 69 +++++++++++++++++++++++++++++++---- src/crypto/stm32wba_aes.c | 69 +++++++++++++++++++++++++++++++---- src/crypto/stm32wba_hash.c | 48 +++++++++--------------- wolfHAL/crypto/crypto.h | 50 +++++++++++++++---------- wolfHAL/crypto/stm32n6_cryp.h | 12 ++++-- wolfHAL/crypto/stm32wb_aes.h | 11 ++++-- wolfHAL/crypto/stm32wba_aes.h | 11 ++++-- 20 files changed, 385 insertions(+), 122 deletions(-) diff --git a/src/crypto/aes_cbc.c b/src/crypto/aes_cbc.c index 1a9ad2d..ea3607b 100644 --- a/src/crypto/aes_cbc.c +++ b/src/crypto/aes_cbc.c @@ -26,7 +26,9 @@ whal_Error whal_AesCbc_Oneshot(whal_AesCbc *dev, whal_Crypto_Dir dir, const void *iv, const void *in, void *out, size_t sz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, dir, key, keySz, iv, in, out, sz); } @@ -35,7 +37,9 @@ whal_Error whal_AesCbc_Start(whal_AesCbc *dev, whal_Crypto_Dir dir, const void *key, size_t keySz, const void *iv) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev, dir, key, keySz, iv); } @@ -43,7 +47,9 @@ whal_Error whal_AesCbc_Start(whal_AesCbc *dev, whal_Crypto_Dir dir, whal_Error whal_AesCbc_Process(whal_AesCbc *dev, const void *in, void *out, size_t sz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, out, sz); } diff --git a/src/crypto/aes_ccm.c b/src/crypto/aes_ccm.c index 8cd1c00..f184c02 100644 --- a/src/crypto/aes_ccm.c +++ b/src/crypto/aes_ccm.c @@ -28,7 +28,9 @@ whal_Error whal_AesCcm_Oneshot(whal_AesCcm *dev, whal_Crypto_Dir dir, const void *in, void *out, size_t sz, void *tag, size_t tagSz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, dir, key, keySz, nonce, nonceSz, aad, aadSz, in, out, sz, tag, tagSz); @@ -40,7 +42,9 @@ whal_Error whal_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, const void *aad, size_t aadSz, size_t tagSz, size_t sz) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev, dir, key, keySz, nonce, nonceSz, aad, aadSz, tagSz, sz); @@ -49,7 +53,9 @@ whal_Error whal_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, whal_Error whal_AesCcm_Process(whal_AesCcm *dev, const void *in, void *out, size_t sz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, out, sz); } @@ -57,7 +63,9 @@ whal_Error whal_AesCcm_Process(whal_AesCcm *dev, whal_Error whal_AesCcm_Finalize(whal_AesCcm *dev, void *tag, size_t tagSz) { - if (!dev || !dev->driver || !dev->driver->Finalize) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Finalize) return WHAL_ENOTSUP; return dev->driver->Finalize(dev, tag, tagSz); } diff --git a/src/crypto/aes_ctr.c b/src/crypto/aes_ctr.c index db4e8d5..6824fe1 100644 --- a/src/crypto/aes_ctr.c +++ b/src/crypto/aes_ctr.c @@ -26,7 +26,9 @@ whal_Error whal_AesCtr_Oneshot(whal_AesCtr *dev, whal_Crypto_Dir dir, const void *iv, const void *in, void *out, size_t sz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, dir, key, keySz, iv, in, out, sz); } @@ -35,7 +37,9 @@ whal_Error whal_AesCtr_Start(whal_AesCtr *dev, whal_Crypto_Dir dir, const void *key, size_t keySz, const void *iv) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev, dir, key, keySz, iv); } @@ -43,7 +47,9 @@ whal_Error whal_AesCtr_Start(whal_AesCtr *dev, whal_Crypto_Dir dir, whal_Error whal_AesCtr_Process(whal_AesCtr *dev, const void *in, void *out, size_t sz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, out, sz); } diff --git a/src/crypto/aes_ecb.c b/src/crypto/aes_ecb.c index 1ca0f6d..76109d6 100644 --- a/src/crypto/aes_ecb.c +++ b/src/crypto/aes_ecb.c @@ -25,7 +25,9 @@ whal_Error whal_AesEcb_Oneshot(whal_AesEcb *dev, whal_Crypto_Dir dir, const void *key, size_t keySz, const void *in, void *out, size_t sz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, dir, key, keySz, in, out, sz); } @@ -33,7 +35,9 @@ whal_Error whal_AesEcb_Oneshot(whal_AesEcb *dev, whal_Crypto_Dir dir, whal_Error whal_AesEcb_Start(whal_AesEcb *dev, whal_Crypto_Dir dir, const void *key, size_t keySz) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev, dir, key, keySz); } @@ -41,7 +45,9 @@ whal_Error whal_AesEcb_Start(whal_AesEcb *dev, whal_Crypto_Dir dir, whal_Error whal_AesEcb_Process(whal_AesEcb *dev, const void *in, void *out, size_t sz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, out, sz); } diff --git a/src/crypto/aes_gcm.c b/src/crypto/aes_gcm.c index 1d931f2..3cea3c8 100644 --- a/src/crypto/aes_gcm.c +++ b/src/crypto/aes_gcm.c @@ -28,7 +28,9 @@ whal_Error whal_AesGcm_Oneshot(whal_AesGcm *dev, whal_Crypto_Dir dir, const void *in, void *out, size_t sz, void *tag, size_t tagSz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, dir, key, keySz, iv, ivSz, aad, aadSz, in, out, sz, tag, tagSz); @@ -39,7 +41,9 @@ whal_Error whal_AesGcm_Start(whal_AesGcm *dev, whal_Crypto_Dir dir, const void *iv, size_t ivSz, const void *aad, size_t aadSz) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev, dir, key, keySz, iv, ivSz, aad, aadSz); } @@ -47,7 +51,9 @@ whal_Error whal_AesGcm_Start(whal_AesGcm *dev, whal_Crypto_Dir dir, whal_Error whal_AesGcm_Process(whal_AesGcm *dev, const void *in, void *out, size_t sz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, out, sz); } @@ -55,7 +61,9 @@ whal_Error whal_AesGcm_Process(whal_AesGcm *dev, whal_Error whal_AesGcm_Finalize(whal_AesGcm *dev, void *tag, size_t tagSz) { - if (!dev || !dev->driver || !dev->driver->Finalize) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Finalize) return WHAL_ENOTSUP; return dev->driver->Finalize(dev, tag, tagSz); } diff --git a/src/crypto/aes_gmac.c b/src/crypto/aes_gmac.c index 30fde4c..f1fc3a1 100644 --- a/src/crypto/aes_gmac.c +++ b/src/crypto/aes_gmac.c @@ -27,7 +27,9 @@ whal_Error whal_AesGmac_Oneshot(whal_AesGmac *dev, const void *aad, size_t aadSz, void *tag, size_t tagSz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, key, keySz, iv, ivSz, aad, aadSz, tag, tagSz); diff --git a/src/crypto/hmac_sha1.c b/src/crypto/hmac_sha1.c index 0e9c9b0..04c784b 100644 --- a/src/crypto/hmac_sha1.c +++ b/src/crypto/hmac_sha1.c @@ -26,7 +26,9 @@ whal_Error whal_HmacSha1_Oneshot(whal_HmacSha1 *dev, const void *in, size_t inSz, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, key, keySz, in, inSz, digest, digestSz); } @@ -34,7 +36,9 @@ whal_Error whal_HmacSha1_Oneshot(whal_HmacSha1 *dev, whal_Error whal_HmacSha1_Start(whal_HmacSha1 *dev, const void *key, size_t keySz) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev, key, keySz); } @@ -42,7 +46,9 @@ whal_Error whal_HmacSha1_Start(whal_HmacSha1 *dev, whal_Error whal_HmacSha1_Process(whal_HmacSha1 *dev, const void *in, size_t inSz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, inSz); } @@ -50,7 +56,9 @@ whal_Error whal_HmacSha1_Process(whal_HmacSha1 *dev, whal_Error whal_HmacSha1_Finalize(whal_HmacSha1 *dev, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Finalize) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Finalize) return WHAL_ENOTSUP; return dev->driver->Finalize(dev, digest, digestSz); } diff --git a/src/crypto/hmac_sha224.c b/src/crypto/hmac_sha224.c index 6ba66e6..5174dc4 100644 --- a/src/crypto/hmac_sha224.c +++ b/src/crypto/hmac_sha224.c @@ -26,7 +26,9 @@ whal_Error whal_HmacSha224_Oneshot(whal_HmacSha224 *dev, const void *in, size_t inSz, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, key, keySz, in, inSz, digest, digestSz); } @@ -34,7 +36,9 @@ whal_Error whal_HmacSha224_Oneshot(whal_HmacSha224 *dev, whal_Error whal_HmacSha224_Start(whal_HmacSha224 *dev, const void *key, size_t keySz) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev, key, keySz); } @@ -42,7 +46,9 @@ whal_Error whal_HmacSha224_Start(whal_HmacSha224 *dev, whal_Error whal_HmacSha224_Process(whal_HmacSha224 *dev, const void *in, size_t inSz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, inSz); } @@ -50,7 +56,9 @@ whal_Error whal_HmacSha224_Process(whal_HmacSha224 *dev, whal_Error whal_HmacSha224_Finalize(whal_HmacSha224 *dev, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Finalize) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Finalize) return WHAL_ENOTSUP; return dev->driver->Finalize(dev, digest, digestSz); } diff --git a/src/crypto/hmac_sha256.c b/src/crypto/hmac_sha256.c index a0a31f7..dc25cd4 100644 --- a/src/crypto/hmac_sha256.c +++ b/src/crypto/hmac_sha256.c @@ -26,7 +26,9 @@ whal_Error whal_HmacSha256_Oneshot(whal_HmacSha256 *dev, const void *in, size_t inSz, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, key, keySz, in, inSz, digest, digestSz); } @@ -34,7 +36,9 @@ whal_Error whal_HmacSha256_Oneshot(whal_HmacSha256 *dev, whal_Error whal_HmacSha256_Start(whal_HmacSha256 *dev, const void *key, size_t keySz) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev, key, keySz); } @@ -42,7 +46,9 @@ whal_Error whal_HmacSha256_Start(whal_HmacSha256 *dev, whal_Error whal_HmacSha256_Process(whal_HmacSha256 *dev, const void *in, size_t inSz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, inSz); } @@ -50,7 +56,9 @@ whal_Error whal_HmacSha256_Process(whal_HmacSha256 *dev, whal_Error whal_HmacSha256_Finalize(whal_HmacSha256 *dev, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Finalize) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Finalize) return WHAL_ENOTSUP; return dev->driver->Finalize(dev, digest, digestSz); } diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c index ffeb8f3..a1a25e5 100644 --- a/src/crypto/sha1.c +++ b/src/crypto/sha1.c @@ -25,28 +25,36 @@ whal_Error whal_Sha1_Oneshot(whal_Sha1 *dev, const void *in, size_t inSz, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, in, inSz, digest, digestSz); } whal_Error whal_Sha1_Start(whal_Sha1 *dev) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev); } whal_Error whal_Sha1_Process(whal_Sha1 *dev, const void *in, size_t inSz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, inSz); } whal_Error whal_Sha1_Finalize(whal_Sha1 *dev, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Finalize) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Finalize) return WHAL_ENOTSUP; return dev->driver->Finalize(dev, digest, digestSz); } diff --git a/src/crypto/sha224.c b/src/crypto/sha224.c index 69d3ab1..5423819 100644 --- a/src/crypto/sha224.c +++ b/src/crypto/sha224.c @@ -25,21 +25,27 @@ whal_Error whal_Sha224_Oneshot(whal_Sha224 *dev, const void *in, size_t inSz, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, in, inSz, digest, digestSz); } whal_Error whal_Sha224_Start(whal_Sha224 *dev) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev); } whal_Error whal_Sha224_Process(whal_Sha224 *dev, const void *in, size_t inSz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, inSz); } @@ -47,7 +53,9 @@ whal_Error whal_Sha224_Process(whal_Sha224 *dev, const void *in, size_t inSz) whal_Error whal_Sha224_Finalize(whal_Sha224 *dev, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Finalize) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Finalize) return WHAL_ENOTSUP; return dev->driver->Finalize(dev, digest, digestSz); } diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c index 6a989d5..2171cd7 100644 --- a/src/crypto/sha256.c +++ b/src/crypto/sha256.c @@ -25,21 +25,27 @@ whal_Error whal_Sha256_Oneshot(whal_Sha256 *dev, const void *in, size_t inSz, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Oneshot) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Oneshot) return WHAL_ENOTSUP; return dev->driver->Oneshot(dev, in, inSz, digest, digestSz); } whal_Error whal_Sha256_Start(whal_Sha256 *dev) { - if (!dev || !dev->driver || !dev->driver->Start) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Start) return WHAL_ENOTSUP; return dev->driver->Start(dev); } whal_Error whal_Sha256_Process(whal_Sha256 *dev, const void *in, size_t inSz) { - if (!dev || !dev->driver || !dev->driver->Process) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Process) return WHAL_ENOTSUP; return dev->driver->Process(dev, in, inSz); } @@ -47,7 +53,9 @@ whal_Error whal_Sha256_Process(whal_Sha256 *dev, const void *in, size_t inSz) whal_Error whal_Sha256_Finalize(whal_Sha256 *dev, void *digest, size_t digestSz) { - if (!dev || !dev->driver || !dev->driver->Finalize) + if (!dev) + return WHAL_EINVAL; + if (!dev->driver || !dev->driver->Finalize) return WHAL_ENOTSUP; return dev->driver->Finalize(dev, digest, digestSz); } diff --git a/src/crypto/stm32n6_cryp.c b/src/crypto/stm32n6_cryp.c index 6b1f3f6..921fd2f 100644 --- a/src/crypto/stm32n6_cryp.c +++ b/src/crypto/stm32n6_cryp.c @@ -955,6 +955,7 @@ whal_Error whal_Stm32n6_CrypAesGcm_Start(whal_AesGcm *dev, g_aesGcmState.aadSz = aadSz; g_aesGcmState.dataSz = 0; + g_aesGcmState.partial = 0; return WHAL_SUCCESS; @@ -985,6 +986,13 @@ whal_Error whal_Stm32n6_CrypAesGcm_Process(whal_AesGcm *dev, return WHAL_EINVAL; } + /* Only the last Process call may end in a partial block */ + if (g_aesGcmState.partial) { + Disable(base); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + algoDir = whal_GetBits(CRYP_CR_ALGODIR_Msk, CRYP_CR_ALGODIR_Pos, whal_Reg_Read(base, CRYP_CR_REG)); @@ -1026,6 +1034,8 @@ whal_Error whal_Stm32n6_CrypAesGcm_Process(whal_AesGcm *dev, } g_aesGcmState.dataSz += sz; + if (sz & 0xF) + g_aesGcmState.partial = 1; return WHAL_SUCCESS; } @@ -1217,6 +1227,9 @@ whal_Error whal_Stm32n6_CrypAesCcm_Oneshot(whal_AesCcm *dev, return WHAL_EINVAL; if (nonceSz < 7 || nonceSz > 13) return WHAL_EINVAL; + /* The payload length must fit in the q = 15 - nonceSz bytes of B0 */ + if (15 - nonceSz < sizeof(size_t) && (sz >> (8 * (15 - nonceSz))) != 0) + return WHAL_EINVAL; if (tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0) return WHAL_EINVAL; if (aadSz > 0 && !aad) @@ -1281,9 +1294,20 @@ whal_Error whal_Stm32n6_CrypAesCcm_Oneshot(whal_AesCcm *dev, CRYP_GCM_CCMPH_HEADER)); Enable(base); - hdr[0] = (uint8_t)(aadSz >> 8); - hdr[1] = (uint8_t)aadSz; - hdrOff = 2; + /* SP 800-38C A.2.2: 2-byte length below 0xFF00, else 0xFFFE + 4 bytes */ + if (aadSz < 0xFF00) { + hdr[0] = (uint8_t)(aadSz >> 8); + hdr[1] = (uint8_t)aadSz; + hdrOff = 2; + } else { + hdr[0] = 0xFF; + hdr[1] = 0xFE; + hdr[2] = (uint8_t)((uint32_t)aadSz >> 24); + hdr[3] = (uint8_t)((uint32_t)aadSz >> 16); + hdr[4] = (uint8_t)((uint32_t)aadSz >> 8); + hdr[5] = (uint8_t)aadSz; + hdrOff = 6; + } while (hdrOff < 16 && aadOff < aadSz) hdr[hdrOff++] = aadPtr[aadOff++]; WriteBlock(base, hdr); @@ -1398,6 +1422,9 @@ whal_Error whal_Stm32n6_CrypAesCcm_Start(whal_AesCcm *dev, return WHAL_EINVAL; if (nonceSz < 7 || nonceSz > 13) return WHAL_EINVAL; + /* The payload length must fit in the q = 15 - nonceSz bytes of B0 */ + if (15 - nonceSz < sizeof(size_t) && (sz >> (8 * (15 - nonceSz))) != 0) + return WHAL_EINVAL; if (tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0) return WHAL_EINVAL; if (aadSz > 0 && !aad) @@ -1453,9 +1480,20 @@ whal_Error whal_Stm32n6_CrypAesCcm_Start(whal_AesCcm *dev, CRYP_GCM_CCMPH_HEADER)); Enable(base); - hdr[0] = (uint8_t)(aadSz >> 8); - hdr[1] = (uint8_t)aadSz; - hdrOff = 2; + /* SP 800-38C A.2.2: 2-byte length below 0xFF00, else 0xFFFE + 4 bytes */ + if (aadSz < 0xFF00) { + hdr[0] = (uint8_t)(aadSz >> 8); + hdr[1] = (uint8_t)aadSz; + hdrOff = 2; + } else { + hdr[0] = 0xFF; + hdr[1] = 0xFE; + hdr[2] = (uint8_t)((uint32_t)aadSz >> 24); + hdr[3] = (uint8_t)((uint32_t)aadSz >> 16); + hdr[4] = (uint8_t)((uint32_t)aadSz >> 8); + hdr[5] = (uint8_t)aadSz; + hdrOff = 6; + } while (hdrOff < 16 && aadOff < aadSz) hdr[hdrOff++] = aadPtr[aadOff++]; WriteBlock(base, hdr); @@ -1487,6 +1525,9 @@ whal_Error whal_Stm32n6_CrypAesCcm_Start(whal_AesCcm *dev, g_aesCcmState.aadSz = aadSz; g_aesCcmState.dataSz = 0; + g_aesCcmState.msgSz = sz; + g_aesCcmState.tagSz = tagSz; + g_aesCcmState.partial = 0; return WHAL_SUCCESS; @@ -1517,6 +1558,15 @@ whal_Error whal_Stm32n6_CrypAesCcm_Process(whal_AesCcm *dev, return WHAL_EINVAL; } + /* Only the last Process call may end in a partial block, and the + * total may not exceed the payload length declared at Start */ + if (g_aesCcmState.partial || + sz > g_aesCcmState.msgSz - g_aesCcmState.dataSz) { + Disable(base); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + algoDir = whal_GetBits(CRYP_CR_ALGODIR_Msk, CRYP_CR_ALGODIR_Pos, whal_Reg_Read(base, CRYP_CR_REG)); @@ -1559,6 +1609,8 @@ whal_Error whal_Stm32n6_CrypAesCcm_Process(whal_AesCcm *dev, } g_aesCcmState.dataSz += sz; + if (sz & 0xF) + g_aesCcmState.partial = 1; return WHAL_SUCCESS; } @@ -1574,7 +1626,10 @@ whal_Error whal_Stm32n6_CrypAesCcm_Finalize(whal_AesCcm *dev, whal_Error err; (void)dev; - if (!tag || tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0) { + /* Tag length and payload length must match what Start encoded in B0 */ + if (!tag || tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0 || + tagSz != g_aesCcmState.tagSz || + g_aesCcmState.dataSz != g_aesCcmState.msgSz) { Disable(base); ZeroKeyIv(base); return WHAL_EINVAL; diff --git a/src/crypto/stm32wb_aes.c b/src/crypto/stm32wb_aes.c index 07e70de..2ddf314 100644 --- a/src/crypto/stm32wb_aes.c +++ b/src/crypto/stm32wb_aes.c @@ -899,6 +899,7 @@ whal_Error whal_Stm32wb_AesGcm_Start(whal_AesGcm *dev, whal_Crypto_Dir dir, (whal_Stm32wb_AesGcm_State *)whal_Stm32wb_AesGcm_Dev.state; st->aadSz = aadSz; st->dataSz = 0; + st->partial = 0; } return WHAL_SUCCESS; @@ -933,6 +934,13 @@ whal_Error whal_Stm32wb_AesGcm_Process(whal_AesGcm *dev, return WHAL_EINVAL; } + /* Only the last Process call may end in a partial block */ + if (st->partial) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + mode = whal_GetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, whal_Reg_Read(base, AES_CR_REG)); @@ -974,6 +982,8 @@ whal_Error whal_Stm32wb_AesGcm_Process(whal_AesGcm *dev, } st->dataSz += sz; + if (sz & 0xF) + st->partial = 1; return WHAL_SUCCESS; } @@ -1209,6 +1219,10 @@ whal_Error whal_Stm32wb_AesCcm_Oneshot(whal_AesCcm *dev, whal_Crypto_Dir dir, if (nonceSz < 7 || nonceSz > 13) return WHAL_EINVAL; + /* The payload length must fit in the q = 15 - nonceSz bytes of B0 */ + if (15 - nonceSz < sizeof(size_t) && (sz >> (8 * (15 - nonceSz))) != 0) + return WHAL_EINVAL; + if (sz > 0 && (!in || !out)) return WHAL_EINVAL; @@ -1285,9 +1299,20 @@ whal_Error whal_Stm32wb_AesCcm_Oneshot(whal_AesCcm *dev, whal_Crypto_Dir dir, size_t aadOff = 0; size_t j; - hdrBuf[0] = (uint8_t)(aadSz >> 8); - hdrBuf[1] = (uint8_t)(aadSz); - hdrOff = 2; + /* SP 800-38C A.2.2: 2-byte length below 0xFF00, else 0xFFFE + 4 bytes */ + if (aadSz < 0xFF00) { + hdrBuf[0] = (uint8_t)(aadSz >> 8); + hdrBuf[1] = (uint8_t)(aadSz); + hdrOff = 2; + } else { + hdrBuf[0] = 0xFF; + hdrBuf[1] = 0xFE; + hdrBuf[2] = (uint8_t)((uint32_t)aadSz >> 24); + hdrBuf[3] = (uint8_t)((uint32_t)aadSz >> 16); + hdrBuf[4] = (uint8_t)((uint32_t)aadSz >> 8); + hdrBuf[5] = (uint8_t)(aadSz); + hdrOff = 6; + } while (hdrOff < 16 && aadOff < aadSz) { hdrBuf[hdrOff++] = aadBytes[aadOff++]; @@ -1422,6 +1447,10 @@ whal_Error whal_Stm32wb_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, if (nonceSz < 7 || nonceSz > 13) return WHAL_EINVAL; + /* The payload length must fit in the q = 15 - nonceSz bytes of B0 */ + if (15 - nonceSz < sizeof(size_t) && (sz >> (8 * (15 - nonceSz))) != 0) + return WHAL_EINVAL; + if (aadSz > 0 && !aad) return WHAL_EINVAL; @@ -1495,9 +1524,20 @@ whal_Error whal_Stm32wb_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, size_t aadOff = 0; size_t j; - hdrBuf[0] = (uint8_t)(aadSz >> 8); - hdrBuf[1] = (uint8_t)(aadSz); - hdrOff = 2; + /* SP 800-38C A.2.2: 2-byte length below 0xFF00, else 0xFFFE + 4 bytes */ + if (aadSz < 0xFF00) { + hdrBuf[0] = (uint8_t)(aadSz >> 8); + hdrBuf[1] = (uint8_t)(aadSz); + hdrOff = 2; + } else { + hdrBuf[0] = 0xFF; + hdrBuf[1] = 0xFE; + hdrBuf[2] = (uint8_t)((uint32_t)aadSz >> 24); + hdrBuf[3] = (uint8_t)((uint32_t)aadSz >> 16); + hdrBuf[4] = (uint8_t)((uint32_t)aadSz >> 8); + hdrBuf[5] = (uint8_t)(aadSz); + hdrOff = 6; + } while (hdrOff < 16 && aadOff < aadSz) { hdrBuf[hdrOff++] = aadBytes[aadOff++]; @@ -1540,6 +1580,9 @@ whal_Error whal_Stm32wb_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, (whal_Stm32wb_AesCcm_State *)whal_Stm32wb_AesCcm_Dev.state; st->aadSz = aadSz; st->dataSz = 0; + st->msgSz = sz; + st->tagSz = tagSz; + st->partial = 0; } return WHAL_SUCCESS; @@ -1574,6 +1617,14 @@ whal_Error whal_Stm32wb_AesCcm_Process(whal_AesCcm *dev, return WHAL_EINVAL; } + /* Only the last Process call may end in a partial block, and the + * total may not exceed the payload length declared at Start */ + if (st->partial || sz > st->msgSz - st->dataSz) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + mode = whal_GetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, whal_Reg_Read(base, AES_CR_REG)); @@ -1615,6 +1666,8 @@ whal_Error whal_Stm32wb_AesCcm_Process(whal_AesCcm *dev, } st->dataSz += sz; + if (sz & 0xF) + st->partial = 1; return WHAL_SUCCESS; } @@ -1634,7 +1687,9 @@ whal_Error whal_Stm32wb_AesCcm_Finalize(whal_AesCcm *dev, (void)dev; - if (!tag || tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0) { + /* Tag length and payload length must match what Start encoded in B0 */ + if (!tag || tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0 || + tagSz != st->tagSz || st->dataSz != st->msgSz) { whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); ZeroKeyIv(base); return WHAL_EINVAL; diff --git a/src/crypto/stm32wba_aes.c b/src/crypto/stm32wba_aes.c index 593f19a..33a786d 100644 --- a/src/crypto/stm32wba_aes.c +++ b/src/crypto/stm32wba_aes.c @@ -1009,6 +1009,7 @@ whal_Error whal_Stm32wba_AesGcm_Start(whal_AesGcm *dev, whal_Crypto_Dir dir, (whal_Stm32wba_AesGcm_State *)whal_Stm32wba_AesGcm_Dev.state; st->aadSz = aadSz; st->dataSz = 0; + st->partial = 0; } return WHAL_SUCCESS; @@ -1043,6 +1044,13 @@ whal_Error whal_Stm32wba_AesGcm_Process(whal_AesGcm *dev, return WHAL_EINVAL; } + /* Only the last Process call may end in a partial block */ + if (st->partial) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + mode = whal_GetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, whal_Reg_Read(base, AES_CR_REG)); @@ -1084,6 +1092,8 @@ whal_Error whal_Stm32wba_AesGcm_Process(whal_AesGcm *dev, } st->dataSz += sz; + if (sz & 0xF) + st->partial = 1; return WHAL_SUCCESS; } @@ -1321,6 +1331,10 @@ whal_Error whal_Stm32wba_AesCcm_Oneshot(whal_AesCcm *dev, whal_Crypto_Dir dir, if (nonceSz < 7 || nonceSz > 13) return WHAL_EINVAL; + /* The payload length must fit in the q = 15 - nonceSz bytes of B0 */ + if (15 - nonceSz < sizeof(size_t) && (sz >> (8 * (15 - nonceSz))) != 0) + return WHAL_EINVAL; + if (sz > 0 && (!in || !out)) return WHAL_EINVAL; @@ -1399,9 +1413,20 @@ whal_Error whal_Stm32wba_AesCcm_Oneshot(whal_AesCcm *dev, whal_Crypto_Dir dir, size_t aadOff = 0; size_t j; - hdrBuf[0] = (uint8_t)(aadSz >> 8); - hdrBuf[1] = (uint8_t)(aadSz); - hdrOff = 2; + /* SP 800-38C A.2.2: 2-byte length below 0xFF00, else 0xFFFE + 4 bytes */ + if (aadSz < 0xFF00) { + hdrBuf[0] = (uint8_t)(aadSz >> 8); + hdrBuf[1] = (uint8_t)(aadSz); + hdrOff = 2; + } else { + hdrBuf[0] = 0xFF; + hdrBuf[1] = 0xFE; + hdrBuf[2] = (uint8_t)((uint32_t)aadSz >> 24); + hdrBuf[3] = (uint8_t)((uint32_t)aadSz >> 16); + hdrBuf[4] = (uint8_t)((uint32_t)aadSz >> 8); + hdrBuf[5] = (uint8_t)(aadSz); + hdrOff = 6; + } while (hdrOff < 16 && aadOff < aadSz) { hdrBuf[hdrOff++] = aadBytes[aadOff++]; @@ -1536,6 +1561,10 @@ whal_Error whal_Stm32wba_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, if (nonceSz < 7 || nonceSz > 13) return WHAL_EINVAL; + /* The payload length must fit in the q = 15 - nonceSz bytes of B0 */ + if (15 - nonceSz < sizeof(size_t) && (sz >> (8 * (15 - nonceSz))) != 0) + return WHAL_EINVAL; + if (aadSz > 0 && !aad) return WHAL_EINVAL; @@ -1611,9 +1640,20 @@ whal_Error whal_Stm32wba_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, size_t aadOff = 0; size_t j; - hdrBuf[0] = (uint8_t)(aadSz >> 8); - hdrBuf[1] = (uint8_t)(aadSz); - hdrOff = 2; + /* SP 800-38C A.2.2: 2-byte length below 0xFF00, else 0xFFFE + 4 bytes */ + if (aadSz < 0xFF00) { + hdrBuf[0] = (uint8_t)(aadSz >> 8); + hdrBuf[1] = (uint8_t)(aadSz); + hdrOff = 2; + } else { + hdrBuf[0] = 0xFF; + hdrBuf[1] = 0xFE; + hdrBuf[2] = (uint8_t)((uint32_t)aadSz >> 24); + hdrBuf[3] = (uint8_t)((uint32_t)aadSz >> 16); + hdrBuf[4] = (uint8_t)((uint32_t)aadSz >> 8); + hdrBuf[5] = (uint8_t)(aadSz); + hdrOff = 6; + } while (hdrOff < 16 && aadOff < aadSz) { hdrBuf[hdrOff++] = aadBytes[aadOff++]; @@ -1656,6 +1696,9 @@ whal_Error whal_Stm32wba_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, (whal_Stm32wba_AesCcm_State *)whal_Stm32wba_AesCcm_Dev.state; st->aadSz = aadSz; st->dataSz = 0; + st->msgSz = sz; + st->tagSz = tagSz; + st->partial = 0; } return WHAL_SUCCESS; @@ -1690,6 +1733,14 @@ whal_Error whal_Stm32wba_AesCcm_Process(whal_AesCcm *dev, return WHAL_EINVAL; } + /* Only the last Process call may end in a partial block, and the + * total may not exceed the payload length declared at Start */ + if (st->partial || sz > st->msgSz - st->dataSz) { + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + ZeroKeyIv(base); + return WHAL_EINVAL; + } + mode = whal_GetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, whal_Reg_Read(base, AES_CR_REG)); @@ -1731,6 +1782,8 @@ whal_Error whal_Stm32wba_AesCcm_Process(whal_AesCcm *dev, } st->dataSz += sz; + if (sz & 0xF) + st->partial = 1; return WHAL_SUCCESS; } @@ -1750,7 +1803,9 @@ whal_Error whal_Stm32wba_AesCcm_Finalize(whal_AesCcm *dev, (void)dev; - if (!tag || tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0) { + /* Tag length and payload length must match what Start encoded in B0 */ + if (!tag || tagSz < 4 || tagSz > 16 || (tagSz & 1) != 0 || + tagSz != st->tagSz || st->dataSz != st->msgSz) { whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); ZeroKeyIv(base); return WHAL_EINVAL; diff --git a/src/crypto/stm32wba_hash.c b/src/crypto/stm32wba_hash.c index 8a725a9..e48f48d 100644 --- a/src/crypto/stm32wba_hash.c +++ b/src/crypto/stm32wba_hash.c @@ -260,7 +260,8 @@ whal_Error whal_Stm32wba_Sha1_Oneshot(whal_Sha1 *dev, whal_Error err; (void)dev; - if (!digest || digestSz != 20) + if (!digest || digestSz != 20 || + (inSz > 0 && !in)) return WHAL_EINVAL; whal_Reg_Update(base, HASH_STR_REG, HASH_STR_NBLW_Msk, 0); @@ -270,11 +271,8 @@ whal_Error whal_Stm32wba_Sha1_Oneshot(whal_Sha1 *dev, HASH_CR_MODE_Msk | HASH_CR_LKEY_Msk | HASH_CR_INIT_Msk, AlgoBits(HASH_ALGO_SHA1) | HASH_CR_INIT_Msk); - if (inSz > 0) { - if (!in) - return WHAL_EINVAL; + if (inSz > 0) WriteTail(base, (const uint8_t *)in, inSz); - } whal_Reg_Update(base, HASH_STR_REG, HASH_STR_DCAL_Msk, HASH_STR_DCAL_Msk); @@ -360,7 +358,8 @@ whal_Error whal_Stm32wba_Sha224_Oneshot(whal_Sha224 *dev, whal_Error err; (void)dev; - if (!digest || digestSz != 28) + if (!digest || digestSz != 28 || + (inSz > 0 && !in)) return WHAL_EINVAL; whal_Reg_Update(base, HASH_STR_REG, HASH_STR_NBLW_Msk, 0); @@ -370,11 +369,8 @@ whal_Error whal_Stm32wba_Sha224_Oneshot(whal_Sha224 *dev, HASH_CR_MODE_Msk | HASH_CR_LKEY_Msk | HASH_CR_INIT_Msk, AlgoBits(HASH_ALGO_SHA224) | HASH_CR_INIT_Msk); - if (inSz > 0) { - if (!in) - return WHAL_EINVAL; + if (inSz > 0) WriteTail(base, (const uint8_t *)in, inSz); - } whal_Reg_Update(base, HASH_STR_REG, HASH_STR_DCAL_Msk, HASH_STR_DCAL_Msk); @@ -460,7 +456,8 @@ whal_Error whal_Stm32wba_Sha256_Oneshot(whal_Sha256 *dev, whal_Error err; (void)dev; - if (!digest || digestSz != 32) + if (!digest || digestSz != 32 || + (inSz > 0 && !in)) return WHAL_EINVAL; whal_Reg_Update(base, HASH_STR_REG, HASH_STR_NBLW_Msk, 0); @@ -470,11 +467,8 @@ whal_Error whal_Stm32wba_Sha256_Oneshot(whal_Sha256 *dev, HASH_CR_MODE_Msk | HASH_CR_LKEY_Msk | HASH_CR_INIT_Msk, AlgoBits(HASH_ALGO_SHA256) | HASH_CR_INIT_Msk); - if (inSz > 0) { - if (!in) - return WHAL_EINVAL; + if (inSz > 0) WriteTail(base, (const uint8_t *)in, inSz); - } whal_Reg_Update(base, HASH_STR_REG, HASH_STR_DCAL_Msk, HASH_STR_DCAL_Msk); @@ -562,7 +556,8 @@ whal_Error whal_Stm32wba_HmacSha1_Oneshot(whal_HmacSha1 *dev, whal_Error err; (void)dev; - if (!key || !digest || digestSz != 20) + if (!key || !digest || digestSz != 20 || + (inSz > 0 && !in)) return WHAL_EINVAL; lkey = (keySz > 64) ? 1 : 0; @@ -590,11 +585,8 @@ whal_Error whal_Stm32wba_HmacSha1_Oneshot(whal_HmacSha1 *dev, /* Message */ whal_Reg_Update(base, HASH_STR_REG, HASH_STR_NBLW_Msk, 0); - if (inSz > 0) { - if (!in) - return WHAL_EINVAL; + if (inSz > 0) WriteTail(base, (const uint8_t *)in, inSz); - } whal_Reg_Update(base, HASH_STR_REG, HASH_STR_DCAL_Msk, HASH_STR_DCAL_Msk); @@ -734,7 +726,8 @@ whal_Error whal_Stm32wba_HmacSha224_Oneshot(whal_HmacSha224 *dev, whal_Error err; (void)dev; - if (!key || !digest || digestSz != 28) + if (!key || !digest || digestSz != 28 || + (inSz > 0 && !in)) return WHAL_EINVAL; lkey = (keySz > 64) ? 1 : 0; @@ -762,11 +755,8 @@ whal_Error whal_Stm32wba_HmacSha224_Oneshot(whal_HmacSha224 *dev, /* Message */ whal_Reg_Update(base, HASH_STR_REG, HASH_STR_NBLW_Msk, 0); - if (inSz > 0) { - if (!in) - return WHAL_EINVAL; + if (inSz > 0) WriteTail(base, (const uint8_t *)in, inSz); - } whal_Reg_Update(base, HASH_STR_REG, HASH_STR_DCAL_Msk, HASH_STR_DCAL_Msk); @@ -906,7 +896,8 @@ whal_Error whal_Stm32wba_HmacSha256_Oneshot(whal_HmacSha256 *dev, whal_Error err; (void)dev; - if (!key || !digest || digestSz != 32) + if (!key || !digest || digestSz != 32 || + (inSz > 0 && !in)) return WHAL_EINVAL; lkey = (keySz > 64) ? 1 : 0; @@ -934,11 +925,8 @@ whal_Error whal_Stm32wba_HmacSha256_Oneshot(whal_HmacSha256 *dev, /* Message */ whal_Reg_Update(base, HASH_STR_REG, HASH_STR_NBLW_Msk, 0); - if (inSz > 0) { - if (!in) - return WHAL_EINVAL; + if (inSz > 0) WriteTail(base, (const uint8_t *)in, inSz); - } whal_Reg_Update(base, HASH_STR_REG, HASH_STR_DCAL_Msk, HASH_STR_DCAL_Msk); diff --git a/wolfHAL/crypto/crypto.h b/wolfHAL/crypto/crypto.h index e09e444..60f5863 100644 --- a/wolfHAL/crypto/crypto.h +++ b/wolfHAL/crypto/crypto.h @@ -244,7 +244,7 @@ struct whal_AesCtr { * @param key Key buffer. * @param keySz Key size in bytes. * @param iv Initial counter block (16 bytes). - * @param in Input data. + * @param in Input data (multiple of 16 bytes). * @param out Output buffer. * @param sz Data size in bytes. */ @@ -268,7 +268,7 @@ whal_Error whal_AesCtr_Start(whal_AesCtr *dev, whal_Crypto_Dir dir, * @brief Process data through an active AES-CTR session. * * @param dev AES-CTR device instance. - * @param in Input data. + * @param in Input data (multiple of 16 bytes). * @param out Output buffer. * @param sz Data size in bytes. */ @@ -354,7 +354,8 @@ whal_Error whal_AesGcm_Start(whal_AesGcm *dev, whal_Crypto_Dir dir, * @param dev AES-GCM device instance. * @param in Input data. * @param out Output buffer. - * @param sz Data size in bytes. + * @param sz Data size in bytes. Every call except the last must be a + * multiple of 16 bytes. */ whal_Error whal_AesGcm_Process(whal_AesGcm *dev, const void *in, void *out, size_t sz); @@ -479,8 +480,9 @@ whal_Error whal_AesCcm_Oneshot(whal_AesCcm *dev, whal_Crypto_Dir dir, * @param nonceSz Nonce size in bytes (7-13). * @param aad Additional authenticated data. * @param aadSz AAD size in bytes. - * @param tagSz Tag size (needed for B0 block construction). - * @param sz Total payload size (needed for B0 block construction). + * @param tagSz Tag size (encoded in B0); Finalize must pass the same value. + * @param sz Total payload size (encoded in B0); the Process calls must + * add up to exactly this many bytes. */ whal_Error whal_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, const void *key, size_t keySz, @@ -493,7 +495,8 @@ whal_Error whal_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, * @param dev AES-CCM device instance. * @param in Input data. * @param out Output buffer. - * @param sz Data size in bytes. + * @param sz Data size in bytes. Every call except the last must be a + * multiple of 16 bytes. */ whal_Error whal_AesCcm_Process(whal_AesCcm *dev, const void *in, void *out, size_t sz); @@ -502,7 +505,7 @@ whal_Error whal_AesCcm_Process(whal_AesCcm *dev, * * @param dev AES-CCM device instance. * @param tag Authentication tag output. - * @param tagSz Tag size in bytes. + * @param tagSz Tag size in bytes; must match the tagSz passed to Start. */ whal_Error whal_AesCcm_Finalize(whal_AesCcm *dev, void *tag, size_t tagSz); @@ -538,7 +541,7 @@ struct whal_Sha1 { * @param in Input data. * @param inSz Input size in bytes. * @param digest Output buffer. - * @param digestSz Output buffer size (must be >= 20). + * @param digestSz Output buffer size (must be 20). */ whal_Error whal_Sha1_Oneshot(whal_Sha1 *dev, const void *in, size_t inSz, @@ -562,7 +565,7 @@ whal_Error whal_Sha1_Process(whal_Sha1 *dev, const void *in, size_t inSz); * * @param dev SHA-1 device instance. * @param digest Output buffer. - * @param digestSz Output buffer size (must be >= 20). + * @param digestSz Output buffer size (must be 20). */ whal_Error whal_Sha1_Finalize(whal_Sha1 *dev, void *digest, size_t digestSz); @@ -597,7 +600,7 @@ struct whal_Sha224 { * @param in Input data. * @param inSz Input size in bytes. * @param digest Output buffer. - * @param digestSz Output buffer size (must be >= 28). + * @param digestSz Output buffer size (must be 28). */ whal_Error whal_Sha224_Oneshot(whal_Sha224 *dev, const void *in, size_t inSz, @@ -621,7 +624,7 @@ whal_Error whal_Sha224_Process(whal_Sha224 *dev, const void *in, size_t inSz); * * @param dev SHA-224 device instance. * @param digest Output buffer. - * @param digestSz Output buffer size (must be >= 28). + * @param digestSz Output buffer size (must be 28). */ whal_Error whal_Sha224_Finalize(whal_Sha224 *dev, void *digest, size_t digestSz); @@ -657,7 +660,7 @@ struct whal_Sha256 { * @param in Input data. * @param inSz Input size in bytes. * @param digest Output buffer. - * @param digestSz Output buffer size (must be >= 32). + * @param digestSz Output buffer size (must be 32). */ whal_Error whal_Sha256_Oneshot(whal_Sha256 *dev, const void *in, size_t inSz, @@ -681,7 +684,7 @@ whal_Error whal_Sha256_Process(whal_Sha256 *dev, const void *in, size_t inSz); * * @param dev SHA-256 device instance. * @param digest Output buffer. - * @param digestSz Output buffer size (must be >= 32). + * @param digestSz Output buffer size (must be 32). */ whal_Error whal_Sha256_Finalize(whal_Sha256 *dev, void *digest, size_t digestSz); @@ -725,7 +728,7 @@ struct whal_HmacSha1 { * @param in Input data. * @param inSz Input size in bytes. * @param digest Output MAC buffer. - * @param digestSz Output buffer size (must be >= 20). + * @param digestSz Output buffer size (must be 20). */ whal_Error whal_HmacSha1_Oneshot(whal_HmacSha1 *dev, const void *key, size_t keySz, @@ -734,6 +737,9 @@ whal_Error whal_HmacSha1_Oneshot(whal_HmacSha1 *dev, /** * @brief Start an HMAC-SHA-1 streaming session (load key). * + * The key buffer is read again by Finalize, so it must stay valid and + * unchanged until Finalize returns. + * * @param dev HMAC-SHA-1 device instance. * @param key Key buffer. * @param keySz Key size in bytes. @@ -754,7 +760,7 @@ whal_Error whal_HmacSha1_Process(whal_HmacSha1 *dev, * * @param dev HMAC-SHA-1 device instance. * @param digest Output MAC buffer. - * @param digestSz Output buffer size (must be >= 20). + * @param digestSz Output buffer size (must be 20). */ whal_Error whal_HmacSha1_Finalize(whal_HmacSha1 *dev, void *digest, size_t digestSz); @@ -798,7 +804,7 @@ struct whal_HmacSha224 { * @param in Input data. * @param inSz Input size in bytes. * @param digest Output MAC buffer. - * @param digestSz Output buffer size (must be >= 28). + * @param digestSz Output buffer size (must be 28). */ whal_Error whal_HmacSha224_Oneshot(whal_HmacSha224 *dev, const void *key, size_t keySz, @@ -807,6 +813,9 @@ whal_Error whal_HmacSha224_Oneshot(whal_HmacSha224 *dev, /** * @brief Start an HMAC-SHA-224 streaming session (load key). * + * The key buffer is read again by Finalize, so it must stay valid and + * unchanged until Finalize returns. + * * @param dev HMAC-SHA-224 device instance. * @param key Key buffer. * @param keySz Key size in bytes. @@ -827,7 +836,7 @@ whal_Error whal_HmacSha224_Process(whal_HmacSha224 *dev, * * @param dev HMAC-SHA-224 device instance. * @param digest Output MAC buffer. - * @param digestSz Output buffer size (must be >= 28). + * @param digestSz Output buffer size (must be 28). */ whal_Error whal_HmacSha224_Finalize(whal_HmacSha224 *dev, void *digest, size_t digestSz); @@ -871,7 +880,7 @@ struct whal_HmacSha256 { * @param in Input data. * @param inSz Input size in bytes. * @param digest Output MAC buffer. - * @param digestSz Output buffer size (must be >= 32). + * @param digestSz Output buffer size (must be 32). */ whal_Error whal_HmacSha256_Oneshot(whal_HmacSha256 *dev, const void *key, size_t keySz, @@ -880,6 +889,9 @@ whal_Error whal_HmacSha256_Oneshot(whal_HmacSha256 *dev, /** * @brief Start an HMAC-SHA-256 streaming session (load key). * + * The key buffer is read again by Finalize, so it must stay valid and + * unchanged until Finalize returns. + * * @param dev HMAC-SHA-256 device instance. * @param key Key buffer. * @param keySz Key size in bytes. @@ -900,7 +912,7 @@ whal_Error whal_HmacSha256_Process(whal_HmacSha256 *dev, * * @param dev HMAC-SHA-256 device instance. * @param digest Output MAC buffer. - * @param digestSz Output buffer size (must be >= 32). + * @param digestSz Output buffer size (must be 32). */ whal_Error whal_HmacSha256_Finalize(whal_HmacSha256 *dev, void *digest, size_t digestSz); diff --git a/wolfHAL/crypto/stm32n6_cryp.h b/wolfHAL/crypto/stm32n6_cryp.h index 6c65ba0..4423889 100644 --- a/wolfHAL/crypto/stm32n6_cryp.h +++ b/wolfHAL/crypto/stm32n6_cryp.h @@ -30,8 +30,8 @@ * @brief STM32N6 CRYP (cryptographic processor) driver. * * The CRYP peripheral on the STM32N6 supports AES-128/192/256 in ECB, CBC, - * CTR, GCM, GMAC, and CCM chaining modes. Each algorithm is exposed through - * a per-algorithm vtable with Oneshot/Start/Process/Finalize operations. + * CTR, GCM, GMAC, and CCM chaining modes. ECB/CBC/CTR expose + * Oneshot/Start/Process, GMAC exposes Oneshot, and GCM/CCM add Finalize. */ /** @@ -49,18 +49,22 @@ typedef struct { typedef struct { size_t aadSz; size_t dataSz; + uint8_t partial; /* A partial block was processed; no further Process */ } whal_Stm32n6_AesGcm_State; /** * @brief AES-CCM streaming state. * * @c ccmCtr0 is computed from the nonce in Start and replayed by Finalize for - * the tag's final-phase counter. @c aadSz / @c dataSz feed the final-phase - * length encoding. + * the tag's final-phase counter. @c msgSz and @c tagSz are the values Start + * encoded in B0; @c dataSz counts processed bytes so Finalize can check them. */ typedef struct { size_t aadSz; size_t dataSz; + size_t msgSz; + size_t tagSz; + uint8_t partial; /* A partial block was processed; no further Process */ uint8_t ccmCtr0[16]; } whal_Stm32n6_AesCcm_State; diff --git a/wolfHAL/crypto/stm32wb_aes.h b/wolfHAL/crypto/stm32wb_aes.h index 60acdcf..0674eb4 100644 --- a/wolfHAL/crypto/stm32wb_aes.h +++ b/wolfHAL/crypto/stm32wb_aes.h @@ -30,8 +30,8 @@ * @brief STM32WB AES hardware accelerator driver. * * The STM32WB AES1 peripheral supports 128/256-bit keys in ECB, CBC, - * CTR, GCM, GMAC, and CCM modes. Each algorithm is exposed through - * a per-algorithm vtable with Oneshot/Start/Process/Finalize operations. + * CTR, GCM, GMAC, and CCM modes. ECB/CBC/CTR expose Oneshot/Start/Process, + * GMAC exposes Oneshot, and GCM/CCM add Finalize. */ /** @@ -49,14 +49,19 @@ typedef struct { typedef struct { size_t aadSz; size_t dataSz; + uint8_t partial; /* A partial block was processed; no further Process */ } whal_Stm32wb_AesGcm_State; /** - * @brief AES-CCM streaming state (aadSz/dataSz for final-phase tag). + * @brief AES-CCM streaming state. msgSz and tagSz are the values Start encoded + * in B0; dataSz counts processed bytes so Finalize can check them. */ typedef struct { size_t aadSz; size_t dataSz; + size_t msgSz; + size_t tagSz; + uint8_t partial; /* A partial block was processed; no further Process */ } whal_Stm32wb_AesCcm_State; /* ---- Direct API mapping ---- */ diff --git a/wolfHAL/crypto/stm32wba_aes.h b/wolfHAL/crypto/stm32wba_aes.h index 3f6a77d..b177fac 100644 --- a/wolfHAL/crypto/stm32wba_aes.h +++ b/wolfHAL/crypto/stm32wba_aes.h @@ -30,8 +30,8 @@ * @brief STM32WBA AES hardware accelerator driver. * * The STM32WBA AES peripheral supports 128/256-bit keys in ECB, CBC, - * CTR, GCM, GMAC, and CCM modes. Each algorithm is exposed through - * a per-algorithm vtable with Oneshot/Start/Process/Finalize operations. + * CTR, GCM, GMAC, and CCM modes. ECB/CBC/CTR expose Oneshot/Start/Process, + * GMAC exposes Oneshot, and GCM/CCM add Finalize. */ /** @@ -49,14 +49,19 @@ typedef struct { typedef struct { size_t aadSz; size_t dataSz; + uint8_t partial; /* A partial block was processed; no further Process */ } whal_Stm32wba_AesGcm_State; /** - * @brief AES-CCM streaming state (aadSz/dataSz for final-phase tag). + * @brief AES-CCM streaming state. msgSz and tagSz are the values Start encoded + * in B0; dataSz counts processed bytes so Finalize can check them. */ typedef struct { size_t aadSz; size_t dataSz; + size_t msgSz; + size_t tagSz; + uint8_t partial; /* A partial block was processed; no further Process */ } whal_Stm32wba_AesCcm_State; /* ---- Direct API mapping ---- */ From 8c12172d8a44bb915183871979e15a61a8ed79d4 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Wed, 7 Oct 2026 12:56:09 -0400 Subject: [PATCH 14/18] [flash, i2c, dma, uart, timer, crypto, pic32cz, stm32] Overflow-safe flash bounds, L1 I2C STOP wait, GPDMA abort, doc sync - Flash: rewrite region checks so addr + dataSz cannot wrap (all on-chip drivers) - L1 I2C StartCom waits for BUSY to clear and only software-resets a bus that stays busy past the timeout - GPDMA Stop aborts an active channel with suspend, idle wait and reset, since software cannot clear EN (WBA, U5, N6); WBA UART-DMA Deinit returns Stop errors before resetting transfer state - SysTick Init rejects cyclesPerTick below 2 - Document the streaming CTR/GCM/CCM rules in the WB, WBA and N6 AES headers, and the full WB/C0 flash Write/Erase return codes --- src/dma/stm32wba_gpdma.c | 15 ++++++++++++++- src/flash/pic32cz_flash.c | 9 ++++++--- src/flash/stm32c0_flash.c | 6 ++++-- src/flash/stm32f0_flash.c | 6 ++++-- src/flash/stm32f4_flash.c | 9 ++++++--- src/flash/stm32h5_flash.c | 9 ++++++--- src/flash/stm32l1_flash.c | 9 ++++++--- src/flash/stm32u5_flash.c | 9 ++++++--- src/flash/stm32wb0_flash.c | 9 ++++++--- src/flash/stm32wb_flash.c | 6 ++++-- src/flash/stm32wba_flash.c | 9 ++++++--- src/i2c/stm32l1_i2c.c | 7 ++++--- src/timer/systick.c | 2 +- src/uart/stm32wba_uart_dma.c | 9 +++++++-- wolfHAL/crypto/stm32n6_cryp.h | 17 ++++++++++------- wolfHAL/crypto/stm32wb_aes.h | 17 ++++++++++------- wolfHAL/crypto/stm32wba_aes.h | 17 ++++++++++------- wolfHAL/dma/dma.h | 5 +++-- wolfHAL/flash/stm32c0_flash.h | 15 +++++++++++---- wolfHAL/flash/stm32wb_flash.h | 15 +++++++++++---- wolfHAL/i2c/stm32l1_i2c.h | 6 ++++-- wolfHAL/timer/systick.h | 2 +- wolfHAL/uart/stm32wba_uart_dma.h | 5 +++-- 23 files changed, 143 insertions(+), 70 deletions(-) diff --git a/src/dma/stm32wba_gpdma.c b/src/dma/stm32wba_gpdma.c index cd75e07..9aabedc 100644 --- a/src/dma/stm32wba_gpdma.c +++ b/src/dma/stm32wba_gpdma.c @@ -300,6 +300,8 @@ whal_Error whal_Stm32wba_Gpdma_Start(whal_Dma *dmaDev, size_t ch) whal_Error whal_Stm32wba_Gpdma_Stop(whal_Dma *dmaDev, size_t ch) { + size_t cr; + whal_Error err; #ifdef WHAL_CFG_STM32WBA_GPDMA_SINGLE_INSTANCE const whal_Stm32wba_Gpdma_Cfg *cfg = (const whal_Stm32wba_Gpdma_Cfg *)whal_Stm32wba_Gpdma_Dev.cfg; @@ -319,7 +321,18 @@ whal_Error whal_Stm32wba_Gpdma_Stop(whal_Dma *dmaDev, size_t ch) if (ch >= cfg->numChannels) return WHAL_EINVAL; - whal_Reg_Update(base, GPDMA_CxCR(ch), GPDMA_CxCR_EN_Msk, 0); + /* EN cannot be cleared by software; abort by suspending, waiting for + * idle, then resetting the channel (RM0493 17.4.4) */ + cr = whal_Reg_Read(base, GPDMA_CxCR(ch)); + if (cr & GPDMA_CxCR_EN_Msk) { + whal_Reg_Write(base, GPDMA_CxCR(ch), + (cr & ~GPDMA_CxCR_EN_Msk) | GPDMA_CxCR_SUSP_Msk); + err = whal_Reg_ReadPoll(base, GPDMA_CxSR(ch), GPDMA_CxSR_IDLEF_Msk, + GPDMA_CxSR_IDLEF_Msk, cfg->timeout); + if (err) + return err; + whal_Reg_Write(base, GPDMA_CxCR(ch), GPDMA_CxCR_RESET_Msk); + } whal_Reg_Write(base, GPDMA_CxFCR(ch), GPDMA_CxFCR_ALL); diff --git a/src/flash/pic32cz_flash.c b/src/flash/pic32cz_flash.c index 4e53d63..12665be 100644 --- a/src/flash/pic32cz_flash.c +++ b/src/flash/pic32cz_flash.c @@ -277,7 +277,8 @@ whal_Error whal_Pic32cz_Flash_Read(whal_Flash *flashDev, size_t addr, void *data return WHAL_EINVAL; } - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; err = whal_Pic32cz_Flash_MutexLock(base, cfg->timeout); @@ -309,7 +310,8 @@ whal_Error whal_Pic32cz_Flash_Write(whal_Flash *flashDev, size_t addr, const voi return WHAL_EINVAL; } - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Require double-word alignment */ @@ -383,7 +385,8 @@ whal_Error whal_Pic32cz_Flash_Erase(whal_Flash *flashDev, size_t addr, size_t da size_t endAddr; (void)flashDev; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; if (dataSz == 0) diff --git a/src/flash/stm32c0_flash.c b/src/flash/stm32c0_flash.c index 834193f..08a8fcf 100644 --- a/src/flash/stm32c0_flash.c +++ b/src/flash/stm32c0_flash.c @@ -185,7 +185,8 @@ whal_Error whal_Stm32c0_Flash_Read(whal_Flash *flashDev, size_t addr, void *data if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Flash is memory-mapped, so reading is a simple memory copy */ @@ -211,7 +212,8 @@ static whal_Error whal_Stm32c0_Flash_WriteOrErase(whal_Flash *flashDev, size_t a size_t bsy; (void)flashDev; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Write requires 8-byte alignment (64-bit double-word programming) */ diff --git a/src/flash/stm32f0_flash.c b/src/flash/stm32f0_flash.c index 9587d14..ae82cb4 100644 --- a/src/flash/stm32f0_flash.c +++ b/src/flash/stm32f0_flash.c @@ -130,7 +130,8 @@ whal_Error whal_Stm32f0_Flash_Read(whal_Flash *flashDev, size_t addr, void *data if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; uint8_t *flashAddr = (uint8_t *)addr; @@ -151,7 +152,8 @@ static whal_Error whal_Stm32f0_Flash_WriteOrErase(whal_Flash *flashDev, size_t bsy; (void)flashDev; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Write requires 2-byte alignment (16-bit half-word programming) */ diff --git a/src/flash/stm32f4_flash.c b/src/flash/stm32f4_flash.c index 60cbb2c..de4ab05 100644 --- a/src/flash/stm32f4_flash.c +++ b/src/flash/stm32f4_flash.c @@ -169,7 +169,8 @@ whal_Error whal_Stm32f4_Flash_Read(whal_Flash *flashDev, size_t addr, if (!data) return WHAL_EINVAL; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; uint8_t *flashAddr = (uint8_t *)addr; @@ -196,7 +197,8 @@ whal_Error whal_Stm32f4_Flash_Write(whal_Flash *flashDev, size_t addr, if ((addr & 0x3) || (dataSz & 0x3)) return WHAL_EINVAL; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Wait for any ongoing operation */ @@ -253,7 +255,8 @@ whal_Error whal_Stm32f4_Flash_Erase(whal_Flash *flashDev, size_t addr, if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Wait for any ongoing operation */ diff --git a/src/flash/stm32h5_flash.c b/src/flash/stm32h5_flash.c index 031858b..de92890 100644 --- a/src/flash/stm32h5_flash.c +++ b/src/flash/stm32h5_flash.c @@ -200,7 +200,8 @@ whal_Error whal_Stm32h5_Flash_Read(whal_Flash *flashDev, size_t addr, if (!data) return WHAL_EINVAL; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; uint8_t *flashAddr = (uint8_t *)addr; @@ -244,7 +245,8 @@ whal_Error whal_Stm32h5_Flash_Write(whal_Flash *flashDev, size_t addr, if ((addr & 0xF) || (dataSz & 0xF)) return WHAL_EINVAL; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Wait for any ongoing operation */ @@ -298,7 +300,8 @@ whal_Error whal_Stm32h5_Flash_Erase(whal_Flash *flashDev, size_t addr, if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Wait for any ongoing operation */ diff --git a/src/flash/stm32l1_flash.c b/src/flash/stm32l1_flash.c index 01689fa..3b25d25 100644 --- a/src/flash/stm32l1_flash.c +++ b/src/flash/stm32l1_flash.c @@ -185,7 +185,8 @@ whal_Error whal_Stm32l1_Flash_Read(whal_Flash *flashDev, size_t addr, void *data if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Flash is memory-mapped, direct read */ @@ -216,7 +217,8 @@ whal_Error whal_Stm32l1_Flash_Write(whal_Flash *flashDev, size_t addr, if ((addr & 0x3) || (dataSz & 0x3)) return WHAL_EINVAL; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Clear error flags */ @@ -260,7 +262,8 @@ whal_Error whal_Stm32l1_Flash_Erase(whal_Flash *flashDev, size_t addr, if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; err = whal_Reg_ReadPoll(base, FLASH_SR_REG, FLASH_SR_BSY_Msk, 0, diff --git a/src/flash/stm32u5_flash.c b/src/flash/stm32u5_flash.c index 0b903dc..04ab707 100644 --- a/src/flash/stm32u5_flash.c +++ b/src/flash/stm32u5_flash.c @@ -164,7 +164,8 @@ whal_Error whal_Stm32u5_Flash_Read(whal_Flash *flashDev, size_t addr, if (!data) return WHAL_EINVAL; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; uint8_t *flashAddr = (uint8_t *)addr; @@ -208,7 +209,8 @@ whal_Error whal_Stm32u5_Flash_Write(whal_Flash *flashDev, size_t addr, if ((addr & 0xF) || (dataSz & 0xF)) return WHAL_EINVAL; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; err = WaitNotBusy(base, cfg->timeout); @@ -262,7 +264,8 @@ whal_Error whal_Stm32u5_Flash_Erase(whal_Flash *flashDev, size_t addr, size_t da if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; err = WaitNotBusy(base, cfg->timeout); diff --git a/src/flash/stm32wb0_flash.c b/src/flash/stm32wb0_flash.c index 510646c..f8e076e 100644 --- a/src/flash/stm32wb0_flash.c +++ b/src/flash/stm32wb0_flash.c @@ -204,7 +204,8 @@ whal_Error whal_Stm32wb0_Flash_Read(whal_Flash *flashDev, size_t addr, return WHAL_EINVAL; if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Flash is memory-mapped; a simple byte copy is fine. */ @@ -228,7 +229,8 @@ whal_Error whal_Stm32wb0_Flash_Write(whal_Flash *flashDev, size_t addr, return WHAL_EINVAL; if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* The WRITE command programs one 32-bit word at a time; address and * size must be word-aligned. */ @@ -266,7 +268,8 @@ whal_Error whal_Stm32wb0_Flash_Erase(whal_Flash *flashDev, size_t addr, if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Round to the page that contains addr, then erase all pages that diff --git a/src/flash/stm32wb_flash.c b/src/flash/stm32wb_flash.c index 122e0eb..a25b0fd 100644 --- a/src/flash/stm32wb_flash.c +++ b/src/flash/stm32wb_flash.c @@ -186,7 +186,8 @@ whal_Error whal_Stm32wb_Flash_Read(whal_Flash *flashDev, size_t addr, void *data if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Flash is memory-mapped, so reading is a simple memory copy */ @@ -216,7 +217,8 @@ static whal_Error whal_Stm32wb_Flash_WriteOrErase(whal_Flash *flashDev, size_t a if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; /* Write requires 8-byte alignment (64-bit double-word programming) */ diff --git a/src/flash/stm32wba_flash.c b/src/flash/stm32wba_flash.c index da779f1..222be31 100644 --- a/src/flash/stm32wba_flash.c +++ b/src/flash/stm32wba_flash.c @@ -161,7 +161,8 @@ whal_Error whal_Stm32wba_Flash_Read(whal_Flash *flashDev, size_t addr, void *dat if (!data) return WHAL_EINVAL; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; uint8_t *flashAddr = (uint8_t *)addr; @@ -210,7 +211,8 @@ whal_Error whal_Stm32wba_Flash_Write(whal_Flash *flashDev, size_t addr, if ((addr & 0xF) || (dataSz & 0xF)) return WHAL_EINVAL; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; err = WaitNotBusy(base, cfg->timeout); @@ -260,7 +262,8 @@ whal_Error whal_Stm32wba_Flash_Erase(whal_Flash *flashDev, size_t addr, size_t d if (dataSz == 0) return WHAL_SUCCESS; - if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + if (addr < cfg->startAddr || dataSz > cfg->size || + addr - cfg->startAddr > cfg->size - dataSz) return WHAL_EINVAL; err = WaitNotBusy(base, cfg->timeout); diff --git a/src/i2c/stm32l1_i2c.c b/src/i2c/stm32l1_i2c.c index 86dc2e3..aad5d6e 100644 --- a/src/i2c/stm32l1_i2c.c +++ b/src/i2c/stm32l1_i2c.c @@ -386,9 +386,10 @@ whal_Error whal_Stm32l1_I2c_StartCom(whal_I2c *i2cDev, whal_I2c_ComCfg *comCfg) base = i2cDev->base; #endif - /* A transfer abandoned on timeout can leave the bus marked busy; only a - * software reset clears that on the V1 peripheral */ - if (whal_Reg_Read(base, I2C_SR2) & SR2_BUSY_Msk) { + /* Let a pending STOP finish; a bus still busy after the timeout was left + * by an abandoned transfer and only a software reset clears it */ + if (whal_Reg_ReadPoll(base, I2C_SR2, SR2_BUSY_Msk, 0, + cfg->timeout) != WHAL_SUCCESS) { whal_Reg_Update(base, I2C_CR1, CR1_SWRST_Msk, CR1_SWRST_Msk); whal_Reg_Update(base, I2C_CR1, CR1_SWRST_Msk, 0); } diff --git a/src/timer/systick.c b/src/timer/systick.c index bcad63d..a432fe6 100644 --- a/src/timer/systick.c +++ b/src/timer/systick.c @@ -63,7 +63,7 @@ whal_Error whal_SysTick_Init(whal_Timer *timerDev) (void)timerDev; /* RELOAD is 24 bits and holds the period minus one */ - if (cfg->cyclesPerTick == 0 || cfg->cyclesPerTick > 0x1000000) + if (cfg->cyclesPerTick < 2 || cfg->cyclesPerTick > 0x1000000) return WHAL_EINVAL; whal_Reg_Update(base, SYSTICK_CSR_REG, diff --git a/src/uart/stm32wba_uart_dma.c b/src/uart/stm32wba_uart_dma.c index c5f402a..bd26458 100644 --- a/src/uart/stm32wba_uart_dma.c +++ b/src/uart/stm32wba_uart_dma.c @@ -272,6 +272,7 @@ whal_Error whal_Stm32wba_UartDma_Deinit(whal_Uart *uartDev) { whal_Stm32wba_UartDma_Cfg *cfg; size_t base; + whal_Error err; #ifdef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE cfg = (whal_Stm32wba_UartDma_Cfg *)whal_Stm32wba_UartDma_Dev.cfg; @@ -287,8 +288,12 @@ whal_Error whal_Stm32wba_UartDma_Deinit(whal_Uart *uartDev) /* Abandon any in-flight transfer so a later Init starts clean */ whal_Reg_Update(base, UART_CR3_REG, UART_CR3_DMAT_Msk | UART_CR3_DMAR_Msk, 0); - whal_Dma_Stop(cfg->dma, cfg->txCh); - whal_Dma_Stop(cfg->dma, cfg->rxCh); + err = whal_Dma_Stop(cfg->dma, cfg->txCh); + if (err) + return err; + err = whal_Dma_Stop(cfg->dma, cfg->rxCh); + if (err) + return err; cfg->txResult = WHAL_SUCCESS; cfg->rxResult = WHAL_SUCCESS; diff --git a/wolfHAL/crypto/stm32n6_cryp.h b/wolfHAL/crypto/stm32n6_cryp.h index 4423889..ff26707 100644 --- a/wolfHAL/crypto/stm32n6_cryp.h +++ b/wolfHAL/crypto/stm32n6_cryp.h @@ -227,7 +227,7 @@ whal_Error whal_Stm32n6_CrypAesCbc_Process(whal_AesCbc *dev, * @param key Key buffer. * @param keySz Key size in bytes (16, 24, or 32). * @param iv Initial counter block (16 bytes). - * @param in Input data. + * @param in Input data (multiple of 16 bytes). * @param out Output buffer. * @param sz Data size in bytes. */ @@ -256,7 +256,7 @@ whal_Error whal_Stm32n6_CrypAesCtr_Start(whal_AesCtr *dev, * @brief Process data through an active AES-CTR session. * * @param dev AES-CTR device instance. - * @param in Input data. + * @param in Input data (multiple of 16 bytes). * @param out Output buffer. * @param sz Data size in bytes. */ @@ -316,7 +316,8 @@ whal_Error whal_Stm32n6_CrypAesGcm_Start(whal_AesGcm *dev, * @param dev AES-GCM device instance. * @param in Input data. * @param out Output buffer. - * @param sz Data size in bytes. + * @param sz Data size in bytes. Every call except the last must be a + * multiple of 16 bytes. */ whal_Error whal_Stm32n6_CrypAesGcm_Process(whal_AesGcm *dev, const void *in, void *out, @@ -392,8 +393,9 @@ whal_Error whal_Stm32n6_CrypAesCcm_Oneshot(whal_AesCcm *dev, * @param nonceSz Nonce size in bytes (7-13). * @param aad Additional authenticated data. * @param aadSz AAD size in bytes. - * @param tagSz Tag size (needed for B0 block construction). - * @param sz Total payload size (needed for B0 block construction). + * @param tagSz Tag size (encoded in B0); Finalize must pass the same value. + * @param sz Total payload size (encoded in B0); the Process calls must + * add up to exactly this many bytes. */ whal_Error whal_Stm32n6_CrypAesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, @@ -408,7 +410,8 @@ whal_Error whal_Stm32n6_CrypAesCcm_Start(whal_AesCcm *dev, * @param dev AES-CCM device instance. * @param in Input data. * @param out Output buffer. - * @param sz Data size in bytes. + * @param sz Data size in bytes. Every call except the last must be a + * multiple of 16 bytes. */ whal_Error whal_Stm32n6_CrypAesCcm_Process(whal_AesCcm *dev, const void *in, void *out, @@ -419,7 +422,7 @@ whal_Error whal_Stm32n6_CrypAesCcm_Process(whal_AesCcm *dev, * * @param dev AES-CCM device instance. * @param tag Authentication tag output. - * @param tagSz Tag size in bytes. + * @param tagSz Tag size in bytes; must match the tagSz passed to Start. */ whal_Error whal_Stm32n6_CrypAesCcm_Finalize(whal_AesCcm *dev, void *tag, size_t tagSz); diff --git a/wolfHAL/crypto/stm32wb_aes.h b/wolfHAL/crypto/stm32wb_aes.h index 0674eb4..8acc1e9 100644 --- a/wolfHAL/crypto/stm32wb_aes.h +++ b/wolfHAL/crypto/stm32wb_aes.h @@ -215,7 +215,7 @@ whal_Error whal_Stm32wb_AesCbc_Process(whal_AesCbc *dev, * @param key Key buffer. * @param keySz Key size in bytes (16 or 32). * @param iv Initial counter block (16 bytes). - * @param in Input data. + * @param in Input data (multiple of 16 bytes). * @param out Output buffer. * @param sz Data size in bytes. */ @@ -241,7 +241,7 @@ whal_Error whal_Stm32wb_AesCtr_Start(whal_AesCtr *dev, whal_Crypto_Dir dir, * @brief Process data through an active AES-CTR session. * * @param dev AES-CTR device instance. - * @param in Input data. + * @param in Input data (multiple of 16 bytes). * @param out Output buffer. * @param sz Data size in bytes. */ @@ -297,7 +297,8 @@ whal_Error whal_Stm32wb_AesGcm_Start(whal_AesGcm *dev, whal_Crypto_Dir dir, * @param dev AES-GCM device instance. * @param in Input data. * @param out Output buffer. - * @param sz Data size in bytes. + * @param sz Data size in bytes. Every call except the last must be a + * multiple of 16 bytes. */ whal_Error whal_Stm32wb_AesGcm_Process(whal_AesGcm *dev, const void *in, void *out, size_t sz); @@ -370,8 +371,9 @@ whal_Error whal_Stm32wb_AesCcm_Oneshot(whal_AesCcm *dev, whal_Crypto_Dir dir, * @param nonceSz Nonce size in bytes (7-13). * @param aad Additional authenticated data. * @param aadSz AAD size in bytes. - * @param tagSz Tag size (needed for B0 block construction). - * @param sz Total payload size (needed for B0 block construction). + * @param tagSz Tag size (encoded in B0); Finalize must pass the same value. + * @param sz Total payload size (encoded in B0); the Process calls must + * add up to exactly this many bytes. */ whal_Error whal_Stm32wb_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, const void *key, size_t keySz, @@ -385,7 +387,8 @@ whal_Error whal_Stm32wb_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, * @param dev AES-CCM device instance. * @param in Input data. * @param out Output buffer. - * @param sz Data size in bytes. + * @param sz Data size in bytes. Every call except the last must be a + * multiple of 16 bytes. */ whal_Error whal_Stm32wb_AesCcm_Process(whal_AesCcm *dev, const void *in, void *out, size_t sz); @@ -395,7 +398,7 @@ whal_Error whal_Stm32wb_AesCcm_Process(whal_AesCcm *dev, * * @param dev AES-CCM device instance. * @param tag Authentication tag output. - * @param tagSz Tag size in bytes. + * @param tagSz Tag size in bytes; must match the tagSz passed to Start. */ whal_Error whal_Stm32wb_AesCcm_Finalize(whal_AesCcm *dev, void *tag, size_t tagSz); diff --git a/wolfHAL/crypto/stm32wba_aes.h b/wolfHAL/crypto/stm32wba_aes.h index b177fac..b640877 100644 --- a/wolfHAL/crypto/stm32wba_aes.h +++ b/wolfHAL/crypto/stm32wba_aes.h @@ -215,7 +215,7 @@ whal_Error whal_Stm32wba_AesCbc_Process(whal_AesCbc *dev, * @param key Key buffer. * @param keySz Key size in bytes (16 or 32). * @param iv Initial counter block (16 bytes). - * @param in Input data. + * @param in Input data (multiple of 16 bytes). * @param out Output buffer. * @param sz Data size in bytes. */ @@ -241,7 +241,7 @@ whal_Error whal_Stm32wba_AesCtr_Start(whal_AesCtr *dev, whal_Crypto_Dir dir, * @brief Process data through an active AES-CTR session. * * @param dev AES-CTR device instance. - * @param in Input data. + * @param in Input data (multiple of 16 bytes). * @param out Output buffer. * @param sz Data size in bytes. */ @@ -297,7 +297,8 @@ whal_Error whal_Stm32wba_AesGcm_Start(whal_AesGcm *dev, whal_Crypto_Dir dir, * @param dev AES-GCM device instance. * @param in Input data. * @param out Output buffer. - * @param sz Data size in bytes. + * @param sz Data size in bytes. Every call except the last must be a + * multiple of 16 bytes. */ whal_Error whal_Stm32wba_AesGcm_Process(whal_AesGcm *dev, const void *in, void *out, size_t sz); @@ -370,8 +371,9 @@ whal_Error whal_Stm32wba_AesCcm_Oneshot(whal_AesCcm *dev, whal_Crypto_Dir dir, * @param nonceSz Nonce size in bytes (7-13). * @param aad Additional authenticated data. * @param aadSz AAD size in bytes. - * @param tagSz Tag size (needed for B0 block construction). - * @param sz Total payload size (needed for B0 block construction). + * @param tagSz Tag size (encoded in B0); Finalize must pass the same value. + * @param sz Total payload size (encoded in B0); the Process calls must + * add up to exactly this many bytes. */ whal_Error whal_Stm32wba_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, const void *key, size_t keySz, @@ -385,7 +387,8 @@ whal_Error whal_Stm32wba_AesCcm_Start(whal_AesCcm *dev, whal_Crypto_Dir dir, * @param dev AES-CCM device instance. * @param in Input data. * @param out Output buffer. - * @param sz Data size in bytes. + * @param sz Data size in bytes. Every call except the last must be a + * multiple of 16 bytes. */ whal_Error whal_Stm32wba_AesCcm_Process(whal_AesCcm *dev, const void *in, void *out, size_t sz); @@ -395,7 +398,7 @@ whal_Error whal_Stm32wba_AesCcm_Process(whal_AesCcm *dev, * * @param dev AES-CCM device instance. * @param tag Authentication tag output. - * @param tagSz Tag size in bytes. + * @param tagSz Tag size in bytes; must match the tagSz passed to Start. */ whal_Error whal_Stm32wba_AesCcm_Finalize(whal_AesCcm *dev, void *tag, size_t tagSz); diff --git a/wolfHAL/dma/dma.h b/wolfHAL/dma/dma.h index 85fc288..eae9734 100644 --- a/wolfHAL/dma/dma.h +++ b/wolfHAL/dma/dma.h @@ -116,8 +116,9 @@ whal_Error whal_Dma_Start(whal_Dma *dmaDev, size_t ch); * @param dmaDev DMA controller instance. * @param ch Channel index. * - * @retval WHAL_SUCCESS Channel stopped. - * @retval WHAL_EINVAL Null pointer or missing driver function. + * @retval WHAL_SUCCESS Channel stopped. + * @retval WHAL_EINVAL Null pointer or missing driver function. + * @retval WHAL_ETIMEOUT The channel did not stop within the timeout. */ whal_Error whal_Dma_Stop(whal_Dma *dmaDev, size_t ch); diff --git a/wolfHAL/flash/stm32c0_flash.h b/wolfHAL/flash/stm32c0_flash.h index 8cb1095..474f803 100644 --- a/wolfHAL/flash/stm32c0_flash.h +++ b/wolfHAL/flash/stm32c0_flash.h @@ -142,8 +142,12 @@ whal_Error whal_Stm32c0_Flash_Read(whal_Flash *flashDev, size_t addr, void *data * @param data Buffer to program. * @param dataSz Number of bytes to program. * - * @retval WHAL_SUCCESS Program completed. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_SUCCESS Program completed. + * @retval WHAL_EINVAL Null pointer, address/size not a multiple of 8, or + * range outside the flash region. + * @retval WHAL_ENOTREADY A previous operation is still in progress (BSY). + * @retval WHAL_ETIMEOUT BSY did not clear within the configured timeout. + * @retval WHAL_EHARDWARE Programming error reported in FLASH_SR. */ whal_Error whal_Stm32c0_Flash_Write(whal_Flash *flashDev, size_t addr, const void *data, size_t dataSz); @@ -157,8 +161,11 @@ whal_Error whal_Stm32c0_Flash_Write(whal_Flash *flashDev, size_t addr, const voi * @param addr Flash address to start erasing. * @param dataSz Number of bytes to erase. * - * @retval WHAL_SUCCESS Erase completed. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_SUCCESS Erase completed. + * @retval WHAL_EINVAL Null pointer or range outside the flash region. + * @retval WHAL_ENOTREADY A previous operation is still in progress (BSY). + * @retval WHAL_ETIMEOUT BSY did not clear within the configured timeout. + * @retval WHAL_EHARDWARE Erase error reported in FLASH_SR. */ whal_Error whal_Stm32c0_Flash_Erase(whal_Flash *flashDev, size_t addr, size_t dataSz); #endif /* !WHAL_CFG_STM32C0_FLASH_DIRECT_API_MAPPING */ diff --git a/wolfHAL/flash/stm32wb_flash.h b/wolfHAL/flash/stm32wb_flash.h index 4ff6fa7..273f16e 100644 --- a/wolfHAL/flash/stm32wb_flash.h +++ b/wolfHAL/flash/stm32wb_flash.h @@ -145,8 +145,12 @@ whal_Error whal_Stm32wb_Flash_Read(whal_Flash *flashDev, size_t addr, void *data * @param data Buffer to program. * @param dataSz Number of bytes to program. * - * @retval WHAL_SUCCESS Program completed. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_SUCCESS Program completed. + * @retval WHAL_EINVAL Null pointer, address/size not a multiple of 8, or + * range outside the flash region. + * @retval WHAL_ENOTREADY Flash busy or program/erase suspended (PESD). + * @retval WHAL_ETIMEOUT BSY did not clear within the configured timeout. + * @retval WHAL_EHARDWARE Programming error reported in FLASH_SR. */ whal_Error whal_Stm32wb_Flash_Write(whal_Flash *flashDev, size_t addr, const void *data, size_t dataSz); @@ -157,8 +161,11 @@ whal_Error whal_Stm32wb_Flash_Write(whal_Flash *flashDev, size_t addr, const voi * @param addr Flash address to start erasing. * @param dataSz Number of bytes to erase. * - * @retval WHAL_SUCCESS Erase completed. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_SUCCESS Erase completed. + * @retval WHAL_EINVAL Null pointer or range outside the flash region. + * @retval WHAL_ENOTREADY Flash busy or program/erase suspended (PESD). + * @retval WHAL_ETIMEOUT BSY did not clear within the configured timeout. + * @retval WHAL_EHARDWARE Erase error reported in FLASH_SR. */ whal_Error whal_Stm32wb_Flash_Erase(whal_Flash *flashDev, size_t addr, size_t dataSz); #endif /* !WHAL_CFG_STM32WB_FLASH_DIRECT_API_MAPPING */ diff --git a/wolfHAL/i2c/stm32l1_i2c.h b/wolfHAL/i2c/stm32l1_i2c.h index 797cdc7..6ca01ed 100644 --- a/wolfHAL/i2c/stm32l1_i2c.h +++ b/wolfHAL/i2c/stm32l1_i2c.h @@ -88,8 +88,10 @@ whal_Error whal_Stm32l1_I2c_Deinit(whal_I2c *i2cDev); /** * @brief Begin a communication session on the STM32L1 I2C peripheral. * - * Computes CCR and TRISE from the configured pclk and the requested - * frequency, then stores the target address for use by Transfer. + * Waits for a pending STOP to clear the bus, software-resetting the + * peripheral if it is still busy after the timeout. Then computes CCR and + * TRISE from the configured pclk and the requested frequency and stores + * the target address for use by Transfer. * * @param i2cDev I2C device instance. * @param comCfg Per-session communication parameters. diff --git a/wolfHAL/timer/systick.h b/wolfHAL/timer/systick.h index bea0fa1..1028317 100644 --- a/wolfHAL/timer/systick.h +++ b/wolfHAL/timer/systick.h @@ -75,7 +75,7 @@ extern const whal_TimerDriver whal_SysTick_Driver; * @param timerDev Timer device instance to initialize. * * @retval WHAL_SUCCESS Initialization completed. - * @retval WHAL_EINVAL cyclesPerTick is 0 or exceeds the 24-bit counter (2^24). + * @retval WHAL_EINVAL cyclesPerTick is below 2 or exceeds the 24-bit counter (2^24). */ whal_Error whal_SysTick_Init(whal_Timer *timerDev); /* diff --git a/wolfHAL/uart/stm32wba_uart_dma.h b/wolfHAL/uart/stm32wba_uart_dma.h index 69b8869..7c9b563 100644 --- a/wolfHAL/uart/stm32wba_uart_dma.h +++ b/wolfHAL/uart/stm32wba_uart_dma.h @@ -85,8 +85,9 @@ extern const whal_UartDriver whal_Stm32wba_UartDma_Driver; * * @param uartDev UART device instance. * - * @retval WHAL_SUCCESS Deinit completed. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_ETIMEOUT A DMA channel did not stop within the timeout. */ whal_Error whal_Stm32wba_UartDma_Deinit(whal_Uart *uartDev); From b85fa56775745c94540a165177ca1f94e98e7076 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Wed, 7 Oct 2026 13:50:47 -0400 Subject: [PATCH 15/18] [uart, flash, stm32f4, stm32l1, test] Skip TC wait on zero-length F4 send, test bounds wraparound - F4/L1 UART Send returns success for zero bytes instead of polling TC - Flash out-of-bounds test adds Read/Write/Erase sizes that make addr + dataSz wrap, so the overflow-safe bounds check is covered --- src/uart/stm32f4_uart.c | 3 +++ tests/flash/test_flash.c | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/uart/stm32f4_uart.c b/src/uart/stm32f4_uart.c index 17d6883..813da48 100644 --- a/src/uart/stm32f4_uart.c +++ b/src/uart/stm32f4_uart.c @@ -169,6 +169,9 @@ whal_Error whal_Stm32f4_Uart_Send(whal_Uart *uartDev, const void *data, size_t d cfg = (whal_Stm32f4_Uart_Cfg *)uartDev->cfg; #endif + if (dataSz == 0) + return WHAL_SUCCESS; + for (size_t i = 0; i < dataSz; ++i) { whal_Error err; diff --git a/tests/flash/test_flash.c b/tests/flash/test_flash.c index 744ac88..18de868 100644 --- a/tests/flash/test_flash.c +++ b/tests/flash/test_flash.c @@ -82,6 +82,7 @@ static void Test_Flash_OutOfBounds(void) { const size_t start = BOARD_FLASH_START_ADDR; const size_t end = BOARD_FLASH_START_ADDR + BOARD_FLASH_SIZE; + const size_t wrapSz = (size_t)0 - (end - 16) + 16; static uint8_t buf[32]; /* Below the region */ @@ -107,6 +108,14 @@ static void Test_Flash_OutOfBounds(void) WHAL_EINVAL); WHAL_ASSERT_EQ(whal_Flash_Erase(g_testFlashDev, end - 16, 32), WHAL_EINVAL); + + /* Size large enough that addr + dataSz wraps around to 16 */ + WHAL_ASSERT_EQ(whal_Flash_Read(g_testFlashDev, end - 16, buf, wrapSz), + WHAL_EINVAL); + WHAL_ASSERT_EQ(whal_Flash_Write(g_testFlashDev, end - 16, buf, wrapSz), + WHAL_EINVAL); + WHAL_ASSERT_EQ(whal_Flash_Erase(g_testFlashDev, end - 16, wrapSz), + WHAL_EINVAL); } static void run_flash_tests(const char *name, int onChip) From b9f990eec5eaa1a34516023132c72f1e0a777f72 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Wed, 7 Oct 2026 17:20:14 -0400 Subject: [PATCH 16/18] [i2c, stm32, test] Reject I2C frequencies above 1 MHz, test little-endian loads - WB-family I2C StartCom returns EINVAL for freq above 1 MHz instead of scaling Fast-mode Plus timings below the spec minimums - Add whal_LoadLe32 cases to the core endian suite --- src/i2c/stm32wb_i2c.c | 3 ++- tests/core/test_endian.c | 35 +++++++++++++++++++++++++++++++++++ wolfHAL/i2c/stm32wb_i2c.h | 2 +- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/i2c/stm32wb_i2c.c b/src/i2c/stm32wb_i2c.c index e15c66e..e32930f 100644 --- a/src/i2c/stm32wb_i2c.c +++ b/src/i2c/stm32wb_i2c.c @@ -478,7 +478,8 @@ whal_Error whal_Stm32wb_I2c_StartCom(whal_I2c *i2cDev, whal_I2c_ComCfg *comCfg) } #endif - if ((comCfg->addrSz != 7 && comCfg->addrSz != 10) || comCfg->freq == 0) { + if ((comCfg->addrSz != 7 && comCfg->addrSz != 10) || comCfg->freq == 0 || + comCfg->freq > 1000000) { return WHAL_EINVAL; } diff --git a/tests/core/test_endian.c b/tests/core/test_endian.c index 372ffe9..c2939a6 100644 --- a/tests/core/test_endian.c +++ b/tests/core/test_endian.c @@ -52,6 +52,36 @@ static void Test_Endian_LoadBe32_LsbOnly(void) WHAL_ASSERT_EQ(whal_LoadBe32(buf), 0x00000001ul); } +static void Test_Endian_LoadLe32(void) +{ + const uint8_t buf[] = { 0xEF, 0xBE, 0xAD, 0xDE }; + WHAL_ASSERT_EQ(whal_LoadLe32(buf), 0xDEADBEEFul); +} + +static void Test_Endian_LoadLe32_Zero(void) +{ + const uint8_t buf[] = { 0x00, 0x00, 0x00, 0x00 }; + WHAL_ASSERT_EQ(whal_LoadLe32(buf), 0x00000000ul); +} + +static void Test_Endian_LoadLe32_AllOnes(void) +{ + const uint8_t buf[] = { 0xFF, 0xFF, 0xFF, 0xFF }; + WHAL_ASSERT_EQ(whal_LoadLe32(buf), 0xFFFFFFFFul); +} + +static void Test_Endian_LoadLe32_MsbOnly(void) +{ + const uint8_t buf[] = { 0x00, 0x00, 0x00, 0x80 }; + WHAL_ASSERT_EQ(whal_LoadLe32(buf), 0x80000000ul); +} + +static void Test_Endian_LoadLe32_LsbOnly(void) +{ + const uint8_t buf[] = { 0x01, 0x00, 0x00, 0x00 }; + WHAL_ASSERT_EQ(whal_LoadLe32(buf), 0x00000001ul); +} + static void Test_Endian_StoreBe32(void) { uint8_t buf[4] = {0}; @@ -97,6 +127,11 @@ void whal_Test_Endian(void) WHAL_TEST(Test_Endian_LoadBe32_AllOnes); WHAL_TEST(Test_Endian_LoadBe32_MsbOnly); WHAL_TEST(Test_Endian_LoadBe32_LsbOnly); + WHAL_TEST(Test_Endian_LoadLe32); + WHAL_TEST(Test_Endian_LoadLe32_Zero); + WHAL_TEST(Test_Endian_LoadLe32_AllOnes); + WHAL_TEST(Test_Endian_LoadLe32_MsbOnly); + WHAL_TEST(Test_Endian_LoadLe32_LsbOnly); WHAL_TEST(Test_Endian_StoreBe32); WHAL_TEST(Test_Endian_StoreBe32_Zero); WHAL_TEST(Test_Endian_StoreBe32_MsbOnly); diff --git a/wolfHAL/i2c/stm32wb_i2c.h b/wolfHAL/i2c/stm32wb_i2c.h index 00d2639..f0097c9 100644 --- a/wolfHAL/i2c/stm32wb_i2c.h +++ b/wolfHAL/i2c/stm32wb_i2c.h @@ -100,7 +100,7 @@ whal_Error whal_Stm32wb_I2c_Deinit(whal_I2c *i2cDev); * @param comCfg Per-session communication parameters. * * @retval WHAL_SUCCESS Communication session started. - * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EINVAL Invalid arguments, or freq is 0 or above 1 MHz. */ whal_Error whal_Stm32wb_I2c_StartCom(whal_I2c *i2cDev, whal_I2c_ComCfg *comCfg); From abe4a0fed6a86f89b7983c4b30a1b5af9dc7c1b5 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Thu, 8 Oct 2026 13:04:51 -0400 Subject: [PATCH 17/18] [rng, stm32] Use AN4230 NIST configuration A on the STM32 RNGs - Add cr, htcr and nscr to the WBA and H5 RNG cfg; Init writes them during CONDRST - Set per-board values from AN4230 Table 3 (WBA55, U5A5, N657, H563) - Drop the hardcoded configuration C (WBA/U5/N6) and H563 values from the drivers --- boards/stm32h563zi_nucleo/wolfHAL_board.h | 4 ++++ boards/stm32n657a0_nucleo/wolfHAL_board.h | 4 ++++ boards/stm32u5a5zj_nucleo/wolfHAL_board.h | 4 ++++ boards/stm32wba55cg_nucleo/wolfHAL_board.h | 4 ++++ src/rng/stm32h5_rng.c | 24 ++++++--------------- src/rng/stm32wba_rng.c | 25 ++++++++-------------- wolfHAL/rng/stm32h5_rng.h | 6 +++++- wolfHAL/rng/stm32wba_rng.h | 14 +++++++++--- 8 files changed, 47 insertions(+), 38 deletions(-) diff --git a/boards/stm32h563zi_nucleo/wolfHAL_board.h b/boards/stm32h563zi_nucleo/wolfHAL_board.h index 4692fc3..4189d91 100644 --- a/boards/stm32h563zi_nucleo/wolfHAL_board.h +++ b/boards/stm32h563zi_nucleo/wolfHAL_board.h @@ -153,9 +153,13 @@ enum { } /* RNG dev initializer — singleton defined in stm32h5_rng.c. */ +/* RNG cr/htcr/nscr: AN4230 Table 3, STM32H563/573/562 */ #define WHAL_CFG_STM32H5_RNG_DEV { \ .base = WHAL_STM32H563_RNG_BASE, \ .cfg = (void *)&(const whal_Stm32h5_Rng_Cfg){ \ + .cr = 0x00F01E00UL, \ + .htcr = 0x00006A91UL, \ + .nscr = 0x0003AF66UL, \ .timeout = &g_whalTimeout, \ }, \ } diff --git a/boards/stm32n657a0_nucleo/wolfHAL_board.h b/boards/stm32n657a0_nucleo/wolfHAL_board.h index af08d8d..70e468e 100644 --- a/boards/stm32n657a0_nucleo/wolfHAL_board.h +++ b/boards/stm32n657a0_nucleo/wolfHAL_board.h @@ -217,9 +217,13 @@ enum { /* RNG dev initializer — singleton defined in stm32wba_rng.c (stm32n6 is * an include alias). */ +/* RNG cr/htcr/nscr: AN4230 Table 3, STM32N6; NSCR "default" is the reset value */ #define WHAL_CFG_STM32N6_RNG_DEV { \ .base = WHAL_STM32N657_RNG_BASE, \ .cfg = (void *)&(const whal_Stm32n6_Rng_Cfg){ \ + .cr = 0x08F00D00UL, \ + .htcr = 0x00006A93UL, \ + .nscr = 0x0003FFFFUL, \ .timeout = &g_whalTimeout, \ }, \ } diff --git a/boards/stm32u5a5zj_nucleo/wolfHAL_board.h b/boards/stm32u5a5zj_nucleo/wolfHAL_board.h index a9f412b..6dfda19 100644 --- a/boards/stm32u5a5zj_nucleo/wolfHAL_board.h +++ b/boards/stm32u5a5zj_nucleo/wolfHAL_board.h @@ -117,9 +117,13 @@ enum { } /* RNG dev initializer — singleton defined in stm32wba_rng.c (alias). */ +/* RNG cr/htcr/nscr: AN4230 Table 3, STM32U59x/5Ax */ #define WHAL_CFG_STM32U5_RNG_DEV { \ .base = WHAL_STM32U5A5_RNG_BASE, \ .cfg = (void *)&(const whal_Stm32u5_Rng_Cfg){ \ + .cr = 0x00F11F00UL, \ + .htcr = 0x000092F3UL, \ + .nscr = 0x00001609UL, \ .timeout = &g_whalTimeout, \ }, \ } diff --git a/boards/stm32wba55cg_nucleo/wolfHAL_board.h b/boards/stm32wba55cg_nucleo/wolfHAL_board.h index 23a96f6..6bd6587 100644 --- a/boards/stm32wba55cg_nucleo/wolfHAL_board.h +++ b/boards/stm32wba55cg_nucleo/wolfHAL_board.h @@ -118,9 +118,13 @@ enum { } /* RNG dev initializer — singleton defined in stm32wba_rng.c. */ +/* RNG cr/htcr/nscr: AN4230 Table 3, STM32WBA5x */ #define WHAL_CFG_STM32WBA_RNG_DEV { \ .base = WHAL_STM32WBA55_RNG_BASE, \ .cfg = (void *)&(const whal_Stm32wba_Rng_Cfg){ \ + .cr = 0x08F01F00UL, \ + .htcr = 0x00006688UL, \ + .nscr = 0x00000FFFUL, \ .timeout = &g_whalTimeout, \ }, \ } diff --git a/src/rng/stm32h5_rng.c b/src/rng/stm32h5_rng.c index 162e668..73702ac 100644 --- a/src/rng/stm32h5_rng.c +++ b/src/rng/stm32h5_rng.c @@ -33,8 +33,7 @@ const whal_Rng whal_Stm32h5_Rng_Dev = WHAL_CFG_STM32H5_RNG_DEV; * STM32H5 RNG Register Definitions * * The STM32H5 RNG has a 4-word output FIFO and requires a CONDRST - * sequence to apply configuration. NIST-certified values from AN4230 - * are used for the STM32H563/573/562 family. + * sequence to apply configuration. */ /* Control Register */ @@ -45,13 +44,6 @@ const whal_Rng whal_Stm32h5_Rng_Dev = WHAL_CFG_STM32H5_RNG_DEV; #define RNG_CR_CONDRST_Pos 30 #define RNG_CR_CONDRST_Msk (1UL << RNG_CR_CONDRST_Pos) -/* - * NIST-certified RNG_CR configuration for STM32H563/573/562 (from AN4230). - * This value encodes CONFIG1=0x0F, CONFIG2=0x0, CONFIG3=0xE, NISTC=1, - * CLKDIV=0, ARDIS=0, CED=0. - */ -#define RNG_CR_NIST_CFG 0x00F01E00UL - /* Status Register */ #define RNG_SR_REG 0x04 #define RNG_SR_DRDY_Pos 0 @@ -75,10 +67,6 @@ const whal_Rng whal_Stm32h5_Rng_Dev = WHAL_CFG_STM32H5_RNG_DEV; /* Health Test Control Register */ #define RNG_HTCR_REG 0x10 -/* NIST-certified HTCR and NSCR values for STM32H563/573/562 (from AN4230) */ -#define RNG_HTCR_NIST_VAL 0x00006A91UL -#define RNG_NSCR_NIST_VAL 0x0003AF66UL - /* Magic value required to unlock HTCR writes */ #define RNG_HTCR_MAGIC 0x17590ABCUL @@ -97,21 +85,21 @@ whal_Error whal_Stm32h5_Rng_Init(whal_Rng *rngDev) (void)rngDev; /* - * Apply NIST-certified configuration via CONDRST sequence: + * Apply the configuration via CONDRST sequence: * 1. Write CONDRST=1 with configuration bits, RNGEN=0 * 2. Write HTCR magic key then HTCR value (while CONDRST=1) * 3. Write NSCR value (while CONDRST=1) * 4. Write CONDRST=0 with RNGEN=1 to start */ whal_Reg_Write(base, RNG_CR_REG, - RNG_CR_NIST_CFG | RNG_CR_CONDRST_Msk); + cfg->cr | RNG_CR_CONDRST_Msk); whal_Reg_Write(base, RNG_HTCR_REG, RNG_HTCR_MAGIC); - whal_Reg_Write(base, RNG_HTCR_REG, RNG_HTCR_NIST_VAL); - whal_Reg_Write(base, RNG_NSCR_REG, RNG_NSCR_NIST_VAL); + whal_Reg_Write(base, RNG_HTCR_REG, cfg->htcr); + whal_Reg_Write(base, RNG_NSCR_REG, cfg->nscr); whal_Reg_Write(base, RNG_CR_REG, - RNG_CR_NIST_CFG | RNG_CR_RNGEN_Msk); + cfg->cr | RNG_CR_RNGEN_Msk); /* Wait for CONDRST to clear (reset complete) */ err = whal_Reg_ReadPoll(base, RNG_CR_REG, diff --git a/src/rng/stm32wba_rng.c b/src/rng/stm32wba_rng.c index 9ad6706..be84bfe 100644 --- a/src/rng/stm32wba_rng.c +++ b/src/rng/stm32wba_rng.c @@ -74,23 +74,15 @@ const whal_Rng whal_Stm32wba_Rng_Dev = WHAL_CFG_STM32WBA_RNG_DEV; /* Data Register (offset 0x008) */ #define RNG_DR_REG 0x08 +/* Noise Source Control Register (offset 0x00C) */ +#define RNG_NSCR_REG 0x0C + /* Health Test Control Register (offset 0x010) */ #define RNG_HTCR_REG 0x10 -/* Configuration C health test value (RM0493 Table 178; same on U5 and N6) */ -#define RNG_HTCR_CONFIG_C 0x0000AAC7UL - /* Magic value written before HTCR (ST HAL, AN4230) */ #define RNG_HTCR_MAGIC 0x17590ABCUL -/* - * Configuration C values (RM0493 Table 178): - * NISTC=0, RNG_CONFIG1=0x0F, CLKDIV=0x0, RNG_CONFIG2=0x0, - * RNG_CONFIG3=0xD, CED=0, N=2 - */ -#define RNG_CR_CONFIG_C (whal_SetBits(RNG_CR_RNG_CONFIG1_Msk, RNG_CR_RNG_CONFIG1_Pos, 0x0F) | \ - whal_SetBits(RNG_CR_RNG_CONFIG3_Msk, RNG_CR_RNG_CONFIG3_Pos, 0x0D)) - #ifdef WHAL_CFG_STM32WBA_RNG_DIRECT_API_MAPPING #define whal_Stm32wba_Rng_Init whal_Rng_Init #define whal_Stm32wba_Rng_Deinit whal_Rng_Deinit @@ -104,17 +96,18 @@ whal_Error whal_Stm32wba_Rng_Init(whal_Rng *rngDev) size_t base = whal_Stm32wba_Rng_Dev.base; (void)rngDev; - /* Apply Configuration C with CONDRST=1 and RNGEN=1 */ + /* Apply the configuration with CONDRST=1 and RNGEN=1 */ whal_Reg_Write(base, RNG_CR_REG, - RNG_CR_CONDRST_Msk | RNG_CR_CONFIG_C | RNG_CR_RNGEN_Msk); + RNG_CR_CONDRST_Msk | cfg->cr | RNG_CR_RNGEN_Msk); - /* HTCR only takes effect while CONDRST is set */ + /* HTCR and NSCR only take effect while CONDRST is set */ whal_Reg_Write(base, RNG_HTCR_REG, RNG_HTCR_MAGIC); - whal_Reg_Write(base, RNG_HTCR_REG, RNG_HTCR_CONFIG_C); + whal_Reg_Write(base, RNG_HTCR_REG, cfg->htcr); + whal_Reg_Write(base, RNG_NSCR_REG, cfg->nscr); /* Clear CONDRST to start conditioning */ whal_Reg_Write(base, RNG_CR_REG, - RNG_CR_CONFIG_C | RNG_CR_RNGEN_Msk); + cfg->cr | RNG_CR_RNGEN_Msk); /* Wait for CONDRST to self-clear */ return whal_Reg_ReadPoll(base, RNG_CR_REG, RNG_CR_CONDRST_Msk, 0, diff --git a/wolfHAL/rng/stm32h5_rng.h b/wolfHAL/rng/stm32h5_rng.h index c9b8ce2..9d6fffc 100644 --- a/wolfHAL/rng/stm32h5_rng.h +++ b/wolfHAL/rng/stm32h5_rng.h @@ -33,13 +33,17 @@ * The STM32H5 true random number generator provides 32-bit random values * from an analog noise source with NIST SP800-90B conditioning. It features * a 4-word output FIFO and requires a CONDRST sequence to apply configuration - * changes. This driver uses the NIST-certified configuration from AN4230. + * changes. The cr, htcr and nscr values are device specific. Use the NIST + * compliant values for the part from AN4230 Table 3. */ /* * @brief RNG device configuration. */ typedef struct whal_Stm32h5_Rng_Cfg { + uint32_t cr; /* RNG_CR configuration bits [29:4] */ + uint32_t htcr; /* RNG_HTCR value */ + uint32_t nscr; /* RNG_NSCR value */ whal_Timeout *timeout; } whal_Stm32h5_Rng_Cfg; diff --git a/wolfHAL/rng/stm32wba_rng.h b/wolfHAL/rng/stm32wba_rng.h index 99c80ab..2a0aee4 100644 --- a/wolfHAL/rng/stm32wba_rng.h +++ b/wolfHAL/rng/stm32wba_rng.h @@ -22,6 +22,7 @@ #ifndef WHAL_STM32WBA_RNG_H #define WHAL_STM32WBA_RNG_H +#include #include #include @@ -31,12 +32,18 @@ * * The RNG kernel clock source must be selected in RCC_CCIPR2.RNGSEL * before using the RNG. Default after reset is LSE (often not enabled). + * + * The cr, htcr and nscr values are device specific. Use the NIST + * compliant values for the part from AN4230 Table 3. */ /* * @brief STM32WBA RNG configuration. */ typedef struct whal_Stm32wba_Rng_Cfg { + uint32_t cr; /* RNG_CR configuration bits [29:4] */ + uint32_t htcr; /* RNG_HTCR value */ + uint32_t nscr; /* RNG_NSCR value */ whal_Timeout *timeout; /* Optional timeout for poll loops */ } whal_Stm32wba_Rng_Cfg; @@ -52,9 +59,10 @@ extern const whal_Rng whal_Stm32wba_Rng_Dev; extern const whal_RngDriver whal_Stm32wba_Rng_Driver; /* - * @brief Initialize the RNG (CONDRST sequence + enable RNGEN). The board - * must have selected a kernel clock source via RCC_CCIPR2.RNGSEL - * before calling this. + * @brief Initialize the RNG (CONDRST sequence + enable RNGEN). Writes the + * configured RNG_CR, RNG_HTCR and RNG_NSCR values. The board must + * have selected a kernel clock source via RCC_CCIPR2.RNGSEL before + * calling this. * * @param rngDev RNG device instance. * From 271354c1babaa1c193bbc74bade9e625a12e5283 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Thu, 8 Oct 2026 13:22:57 -0400 Subject: [PATCH 18/18] [crypto, test] Add AES-128 ECB and CBC known-answer tests - Add Test_AesEcb_KnownAnswer128 (NIST SP 800-38A F.1.1/F.1.2) - Add Test_AesCbc_KnownAnswer128 (NIST SP 800-38A F.2.1/F.2.2) - Each test encrypts and checks the result against the NIST ciphertext, then decrypts back to the plaintext --- tests/crypto/test_aes_cbc.c | 32 ++++++++++++++++++++++++++++++++ tests/crypto/test_aes_ecb.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/tests/crypto/test_aes_cbc.c b/tests/crypto/test_aes_cbc.c index 4faaaaf..cee4290 100644 --- a/tests/crypto/test_aes_cbc.c +++ b/tests/crypto/test_aes_cbc.c @@ -67,6 +67,18 @@ static const uint8_t nistCbcCt[16] = { 0x77, 0x9E, 0xAB, 0xFB, 0x5F, 0x7B, 0xFB, 0xD6, }; +/* NIST SP 800-38A test vectors (AES-128, single block) */ +static const uint8_t nistKey128[16] = { + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C, +}; + +/* NIST SP 800-38A F.2.1 AES-128-CBC expected ciphertext (IV as nistCbcIv) */ +static const uint8_t nistCbcCt128[16] = { + 0x76, 0x49, 0xAB, 0xAC, 0x81, 0x19, 0xB2, 0x46, + 0xCE, 0xE9, 0x8E, 0x9B, 0x12, 0xE9, 0x19, 0x7D, +}; + static void Test_AesCbc_Basic(void) { uint8_t ct[32] = {0}; @@ -96,10 +108,30 @@ static void Test_AesCbc_KnownAnswer(void) WHAL_ASSERT_MEM_EQ(ct, nistCbcCt, sizeof(nistCbcCt)); } +static void Test_AesCbc_KnownAnswer128(void) +{ + uint8_t ct[16] = {0}; + uint8_t pt[16] = {0}; + + WHAL_ASSERT_EQ(whal_AesCbc_Oneshot(BOARD_AES_CBC_DEV, WHAL_CRYPTO_ENCRYPT, + nistKey128, 16, nistCbcIv, nistPt, ct, + sizeof(nistPt)), + WHAL_SUCCESS); + WHAL_ASSERT_MEM_EQ(ct, nistCbcCt128, sizeof(nistCbcCt128)); + + WHAL_ASSERT_EQ(whal_AesCbc_Oneshot(BOARD_AES_CBC_DEV, WHAL_CRYPTO_DECRYPT, + nistKey128, 16, nistCbcIv, + nistCbcCt128, pt, + sizeof(nistCbcCt128)), + WHAL_SUCCESS); + WHAL_ASSERT_MEM_EQ(pt, nistPt, sizeof(nistPt)); +} + void whal_Test_AesCbc(void) { WHAL_TEST_SUITE_START("aes_cbc"); WHAL_TEST(Test_AesCbc_Basic); WHAL_TEST(Test_AesCbc_KnownAnswer); + WHAL_TEST(Test_AesCbc_KnownAnswer128); WHAL_TEST_SUITE_END(); } diff --git a/tests/crypto/test_aes_ecb.c b/tests/crypto/test_aes_ecb.c index 1b6677a..6719ae1 100644 --- a/tests/crypto/test_aes_ecb.c +++ b/tests/crypto/test_aes_ecb.c @@ -57,6 +57,18 @@ static const uint8_t nistEcbCt[16] = { 0x06, 0x4B, 0x5A, 0x7E, 0x3D, 0xB1, 0x81, 0xF8, }; +/* NIST SP 800-38A test vectors (AES-128, single block) */ +static const uint8_t nistKey128[16] = { + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C, +}; + +/* NIST SP 800-38A F.1.1 AES-128-ECB expected ciphertext */ +static const uint8_t nistEcbCt128[16] = { + 0x3A, 0xD7, 0x7B, 0xB4, 0x0D, 0x7A, 0x36, 0x60, + 0xA8, 0x9E, 0xCA, 0xF3, 0x24, 0x66, 0xEF, 0x97, +}; + static void Test_AesEcb_Basic(void) { uint8_t ct[32] = {0}; @@ -86,10 +98,29 @@ static void Test_AesEcb_KnownAnswer(void) WHAL_ASSERT_MEM_EQ(ct, nistEcbCt, sizeof(nistEcbCt)); } +static void Test_AesEcb_KnownAnswer128(void) +{ + uint8_t ct[16] = {0}; + uint8_t pt[16] = {0}; + + WHAL_ASSERT_EQ(whal_AesEcb_Oneshot(BOARD_AES_ECB_DEV, WHAL_CRYPTO_ENCRYPT, + nistKey128, 16, nistPt, ct, + sizeof(nistPt)), + WHAL_SUCCESS); + WHAL_ASSERT_MEM_EQ(ct, nistEcbCt128, sizeof(nistEcbCt128)); + + WHAL_ASSERT_EQ(whal_AesEcb_Oneshot(BOARD_AES_ECB_DEV, WHAL_CRYPTO_DECRYPT, + nistKey128, 16, nistEcbCt128, pt, + sizeof(nistEcbCt128)), + WHAL_SUCCESS); + WHAL_ASSERT_MEM_EQ(pt, nistPt, sizeof(nistPt)); +} + void whal_Test_AesEcb(void) { WHAL_TEST_SUITE_START("aes_ecb"); WHAL_TEST(Test_AesEcb_Basic); WHAL_TEST(Test_AesEcb_KnownAnswer); + WHAL_TEST(Test_AesEcb_KnownAnswer128); WHAL_TEST_SUITE_END(); }