Skip to content

Commit 7c2fa8a

Browse files
committed
Phase 3: flash-backed NVM via whFlashCb adapter over hal_flash_*
Replaces the Phase 1 ramsim NVM with a real flash-backed store living in the existing wolfBoot keyvault region (FLASH_KEYVAULT, 112 KiB at 0x0C040000), so wolfHSM-cached keys persist across reset. - include/wolfboot/wolfhsm_flash_hal.h: whFlashH5Ctx (base / size / partition_size) and whFlashH5_Cb extern. - src/wolfhsm_flash_hal.c: 10-callback whFlashCb adapter wrapping hal_flash_unlock/lock/write/erase. PartitionSize is configurable via the context (default 32 KiB per partition; two partitions = 64 KiB used, 48 KiB headroom in the 112 KiB keyvault). Direct memory reads for Read/Verify/BlankCheck. WriteLock/Unlock are no-ops on H5 (lock is global). - src/wolfhsm_callable.c: drop ramsim ctx/cfg + wh_flash_ramsim include; wire wh_NvmFlashConfig to the new adapter; vault address / size sourced from the linker symbols _flash_keyvault / _flash_keyvault_size, matching the PSA / PKCS11 store pattern. - options.mk: drop wh_flash_ramsim.o, add src/wolfhsm_flash_hal.o. Verified on m33mu with --persist: CommInit handshake + RNG + SHA256 + AES cached-key round-trips all pass through wolfHSM's two-partition journaling layer talking to actual flash. Persistence-across-reset test (P3.3) follows in a separate commit. PKCS11 / PSA / fwTPM regression builds remain clean.
1 parent 4951b9a commit 7c2fa8a

4 files changed

Lines changed: 265 additions & 24 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* wolfhsm_flash_hal.h
2+
*
3+
* Copyright (C) 2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfBoot.
6+
*/
7+
8+
/*
9+
* Adapter that exposes wolfBoot's hal_flash_*() API as a wolfHSM whFlashCb,
10+
* letting the secure-side wolfHSM server persist its NVM in real flash
11+
* instead of the ramsim used during bring-up.
12+
*/
13+
14+
#ifndef WOLFBOOT_WOLFHSM_FLASH_HAL_H
15+
#define WOLFBOOT_WOLFHSM_FLASH_HAL_H
16+
17+
#ifdef WOLFCRYPT_TZ_WOLFHSM
18+
19+
#include <stdint.h>
20+
21+
#include "wolfhsm/wh_flash.h"
22+
23+
typedef struct {
24+
uint32_t base; /* Absolute flash address of the wolfHSM NVM
25+
region (must be 8 KiB-aligned) */
26+
uint32_t size; /* Size of the region in bytes (>= 2 *
27+
partition_size, multiple of 8 KiB) */
28+
uint32_t partition_size; /* Per-partition size in bytes; wolfHSM uses
29+
two partitions (active + backup) for
30+
journaling. Must be a multiple of 8 KiB. */
31+
} whFlashH5Ctx;
32+
33+
extern const whFlashCb whFlashH5_Cb;
34+
35+
#endif /* WOLFCRYPT_TZ_WOLFHSM */
36+
37+
#endif /* WOLFBOOT_WOLFHSM_FLASH_HAL_H */

options.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,7 @@ ifeq ($(WOLFCRYPT_TZ_WOLFHSM),1)
11471147
endif
11481148
WOLFCRYPT_OBJS+=src/store_sbrk.o
11491149
WOLFCRYPT_OBJS+=src/wolfhsm_callable.o
1150+
WOLFCRYPT_OBJS+=src/wolfhsm_flash_hal.o
11501151
WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/cryptocb.o
11511152
WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/coding.o
11521153
WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/hmac.o
@@ -1165,7 +1166,6 @@ ifeq ($(WOLFCRYPT_TZ_WOLFHSM),1)
11651166
endif
11661167
endif
11671168
WOLFHSM_OBJS+=$(WOLFHSM_SERVER_OBJS)
1168-
WOLFHSM_OBJS+=$(WOLFBOOT_LIB_WOLFHSM)/src/wh_flash_ramsim.o
11691169
WOLFHSM_OBJS+=$(WOLFBOOT_LIB_WOLFHSM)/port/stmicro/stm32-tz/wh_transport_nsc.o
11701170
STACK_USAGE=20000
11711171
endif

src/wolfhsm_callable.c

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212

1313
#include "store_sbrk.h"
1414
#include "wolfboot/wcs_wolfhsm.h"
15+
#include "wolfboot/wolfhsm_flash_hal.h"
1516

1617
#include "wolfssl/wolfcrypt/settings.h"
1718
#include "wolfssl/wolfcrypt/random.h"
1819

1920
#include "wolfhsm/wh_comm.h"
2021
#include "wolfhsm/wh_error.h"
2122
#include "wolfhsm/wh_flash.h"
22-
#include "wolfhsm/wh_flash_ramsim.h"
2323
#include "wolfhsm/wh_nvm.h"
2424
#include "wolfhsm/wh_nvm_flash.h"
2525
#include "wolfhsm/wh_server.h"
@@ -36,32 +36,30 @@ void *_sbrk(unsigned int incr)
3636
(uint32_t)(&_heap_size));
3737
}
3838

39-
/* pageSize must match WHFU_BYTES_PER_UNIT (8) — wolfHSM programs the flash
40-
* one unit at a time, so a larger pageSize causes the modulo check in
41-
* whFlashRamsim_Program to fail. */
42-
#define WCS_WOLFHSM_RAMSIM_SIZE (32U * 1024U)
43-
#define WCS_WOLFHSM_RAMSIM_SECTOR (8U * 1024U)
44-
#define WCS_WOLFHSM_RAMSIM_PAGE 8U
45-
46-
#define WCS_WOLFHSM_SERVER_ID 56U
47-
48-
static uint8_t g_ramsim_buf[WCS_WOLFHSM_RAMSIM_SIZE];
49-
static whFlashRamsimCtx g_ramsim_ctx;
50-
static whFlashRamsimCfg g_ramsim_cfg = {
51-
.memory = g_ramsim_buf,
52-
.size = WCS_WOLFHSM_RAMSIM_SIZE,
53-
.sectorSize = WCS_WOLFHSM_RAMSIM_SECTOR,
54-
.pageSize = WCS_WOLFHSM_RAMSIM_PAGE,
55-
.erasedByte = 0xFFU,
56-
.initData = NULL,
39+
#define WCS_WOLFHSM_SERVER_ID 56U
40+
41+
/* Two 32 KiB partitions in the wolfBoot keyvault region: 64 KiB used out of
42+
* 112 KiB, leaving headroom. Per-partition layout = 24 B state header +
43+
* 32 directory entries * 56 B (= ~1.8 KiB) + ~30 KiB usable payload. */
44+
#define WCS_WOLFHSM_PARTITION_SIZE (32U * 1024U)
45+
46+
/* Linker-provided symbols for the FLASH_KEYVAULT region defined in
47+
* hal/stm32h5.ld; matches the PSA / PKCS11 stores' pattern. */
48+
extern uint32_t _flash_keyvault;
49+
extern uint32_t _flash_keyvault_size;
50+
51+
static whFlashH5Ctx g_flash_ctx;
52+
static const whFlashH5Ctx g_flash_cfg = {
53+
.base = (uint32_t)&_flash_keyvault,
54+
.size = (uint32_t)&_flash_keyvault_size,
55+
.partition_size = WCS_WOLFHSM_PARTITION_SIZE,
5756
};
58-
static whFlashCb g_flash_cb = WH_FLASH_RAMSIM_CB;
5957

6058
static whNvmFlashContext g_nvm_flash_ctx;
6159
static whNvmFlashConfig g_nvm_flash_cfg = {
62-
.cb = &g_flash_cb,
63-
.context = &g_ramsim_ctx,
64-
.config = &g_ramsim_cfg,
60+
.cb = &whFlashH5_Cb,
61+
.context = &g_flash_ctx,
62+
.config = &g_flash_cfg,
6563
};
6664
static whNvmCb g_nvm_flash_cb = WH_NVM_FLASH_CB;
6765
static whNvmContext g_nvm_ctx;

src/wolfhsm_flash_hal.c

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/* wolfhsm_flash_hal.c
2+
*
3+
* Copyright (C) 2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfBoot.
6+
*/
7+
8+
#ifdef WOLFCRYPT_TZ_WOLFHSM
9+
10+
#include <stdint.h>
11+
#include <string.h>
12+
13+
#include "hal.h"
14+
#include "wolfboot/wolfhsm_flash_hal.h"
15+
16+
#include "wolfhsm/wh_error.h"
17+
#include "wolfhsm/wh_flash.h"
18+
19+
/*
20+
* STM32H5 page (= erase) size and program-quad-word size. The dual-bank
21+
* H5 erase granularity is 8 KiB; flash programming happens in 16-byte
22+
* quad-word units.
23+
*/
24+
#define WHFH5_SECTOR_SIZE (8U * 1024U)
25+
#define WHFH5_PROGRAM_UNIT 16U
26+
27+
28+
static int _Init(void *context, const void *config)
29+
{
30+
whFlashH5Ctx *ctx = (whFlashH5Ctx *)context;
31+
32+
if (ctx == NULL || config == NULL) {
33+
return WH_ERROR_BADARGS;
34+
}
35+
*ctx = *((const whFlashH5Ctx *)config);
36+
37+
if (ctx->base == 0U || ctx->size == 0U || ctx->partition_size == 0U ||
38+
(ctx->base % WHFH5_SECTOR_SIZE) != 0U ||
39+
(ctx->size % WHFH5_SECTOR_SIZE) != 0U ||
40+
(ctx->partition_size % WHFH5_SECTOR_SIZE) != 0U ||
41+
ctx->size < (uint32_t)2 * ctx->partition_size) {
42+
return WH_ERROR_BADARGS;
43+
}
44+
return WH_ERROR_OK;
45+
}
46+
47+
static int _Cleanup(void *context)
48+
{
49+
if (context == NULL) {
50+
return WH_ERROR_BADARGS;
51+
}
52+
return WH_ERROR_OK;
53+
}
54+
55+
static uint32_t _PartitionSize(void *context)
56+
{
57+
whFlashH5Ctx *ctx = (whFlashH5Ctx *)context;
58+
if (ctx == NULL) {
59+
return 0U;
60+
}
61+
return ctx->partition_size;
62+
}
63+
64+
/*
65+
* STM32H5 has a single global flash unlock; per-region lock/unlock isn't
66+
* available. Program/Erase wrap the unlock+op+lock cycle themselves, so
67+
* the wh_FlashUnit_Program helper's "WriteUnlock around batch of writes"
68+
* pattern is satisfied without per-call hardware action here.
69+
*/
70+
static int _WriteLock(void *context, uint32_t offset, uint32_t size)
71+
{
72+
(void)context;
73+
(void)offset;
74+
(void)size;
75+
return WH_ERROR_OK;
76+
}
77+
78+
static int _WriteUnlock(void *context, uint32_t offset, uint32_t size)
79+
{
80+
(void)context;
81+
(void)offset;
82+
(void)size;
83+
return WH_ERROR_OK;
84+
}
85+
86+
static int _Read(void *context, uint32_t offset, uint32_t size, uint8_t *data)
87+
{
88+
whFlashH5Ctx *ctx = (whFlashH5Ctx *)context;
89+
90+
if (ctx == NULL || (size != 0U && data == NULL)) {
91+
return WH_ERROR_BADARGS;
92+
}
93+
if (offset > ctx->size || size > ctx->size - offset) {
94+
return WH_ERROR_BADARGS;
95+
}
96+
if (size > 0U) {
97+
memcpy(data, (const uint8_t *)(ctx->base + offset), size);
98+
}
99+
return WH_ERROR_OK;
100+
}
101+
102+
static int _Program(void *context, uint32_t offset, uint32_t size,
103+
const uint8_t *data)
104+
{
105+
whFlashH5Ctx *ctx = (whFlashH5Ctx *)context;
106+
int rc;
107+
108+
if (ctx == NULL || (size != 0U && data == NULL)) {
109+
return WH_ERROR_BADARGS;
110+
}
111+
if (offset > ctx->size || size > ctx->size - offset) {
112+
return WH_ERROR_BADARGS;
113+
}
114+
if (size == 0U) {
115+
return WH_ERROR_OK;
116+
}
117+
/* hal_flash_write programs in H5 quad-word (16 byte) chunks; partial
118+
* quad-words at either end fold the existing flash content so any
119+
* `size` is acceptable here. The H5 ECC rule ("each quad-word may be
120+
* programmed at most once between erases") is satisfied as long as
121+
* wolfHSM's unit writes don't share a quad-word, which holds for the
122+
* 32 KiB-aligned partitions / 8-byte units we use. */
123+
hal_flash_unlock();
124+
rc = hal_flash_write(ctx->base + offset, data, (int)size);
125+
hal_flash_lock();
126+
return (rc == 0) ? WH_ERROR_OK : WH_ERROR_ABORTED;
127+
}
128+
129+
static int _Erase(void *context, uint32_t offset, uint32_t size)
130+
{
131+
whFlashH5Ctx *ctx = (whFlashH5Ctx *)context;
132+
int rc;
133+
134+
if (ctx == NULL) {
135+
return WH_ERROR_BADARGS;
136+
}
137+
if (offset > ctx->size || size > ctx->size - offset) {
138+
return WH_ERROR_BADARGS;
139+
}
140+
if ((offset % WHFH5_SECTOR_SIZE) != 0U ||
141+
(size % WHFH5_SECTOR_SIZE) != 0U) {
142+
return WH_ERROR_BADARGS;
143+
}
144+
if (size == 0U) {
145+
return WH_ERROR_OK;
146+
}
147+
148+
hal_flash_unlock();
149+
rc = hal_flash_erase(ctx->base + offset, (int)size);
150+
hal_flash_lock();
151+
return (rc == 0) ? WH_ERROR_OK : WH_ERROR_ABORTED;
152+
}
153+
154+
static int _Verify(void *context, uint32_t offset, uint32_t size,
155+
const uint8_t *data)
156+
{
157+
whFlashH5Ctx *ctx = (whFlashH5Ctx *)context;
158+
159+
if (ctx == NULL || (size != 0U && data == NULL)) {
160+
return WH_ERROR_BADARGS;
161+
}
162+
if (offset > ctx->size || size > ctx->size - offset) {
163+
return WH_ERROR_BADARGS;
164+
}
165+
if (size > 0U &&
166+
memcmp((const uint8_t *)(ctx->base + offset), data, size) != 0) {
167+
return WH_ERROR_NOTVERIFIED;
168+
}
169+
return WH_ERROR_OK;
170+
}
171+
172+
static int _BlankCheck(void *context, uint32_t offset, uint32_t size)
173+
{
174+
whFlashH5Ctx *ctx = (whFlashH5Ctx *)context;
175+
const uint8_t *p;
176+
uint32_t i;
177+
178+
if (ctx == NULL) {
179+
return WH_ERROR_BADARGS;
180+
}
181+
if (offset > ctx->size || size > ctx->size - offset) {
182+
return WH_ERROR_BADARGS;
183+
}
184+
p = (const uint8_t *)(ctx->base + offset);
185+
for (i = 0U; i < size; i++) {
186+
if (p[i] != 0xFFU) {
187+
return WH_ERROR_NOTBLANK;
188+
}
189+
}
190+
return WH_ERROR_OK;
191+
}
192+
193+
const whFlashCb whFlashH5_Cb = {
194+
.Init = _Init,
195+
.Cleanup = _Cleanup,
196+
.PartitionSize = _PartitionSize,
197+
.WriteLock = _WriteLock,
198+
.WriteUnlock = _WriteUnlock,
199+
.Read = _Read,
200+
.Program = _Program,
201+
.Erase = _Erase,
202+
.Verify = _Verify,
203+
.BlankCheck = _BlankCheck,
204+
};
205+
206+
#endif /* WOLFCRYPT_TZ_WOLFHSM */

0 commit comments

Comments
 (0)