1616#include "wolfhsm/wh_error.h"
1717#include "wolfhsm/wh_flash.h"
1818
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
19+ #define WHFH5_SECTOR_SIZE (8U * 1024U)
2620
21+ /* Sector-cached read-modify-erase-write, mirroring psa_store.c. STM32H5
22+ * flash programs in 16-byte quad-words with ECC; each quad-word can be
23+ * programmed exactly once between erases. wolfHSM issues 8-byte unit
24+ * writes which would otherwise re-program neighbouring qwords, so every
25+ * Program call here loads the affected sector into RAM, modifies it, and
26+ * rewrites the whole 8 KiB sector after an erase. */
27+ static uint8_t cached_sector [WHFH5_SECTOR_SIZE ];
2728
2829static int _Init (void * context , const void * config )
2930{
@@ -55,18 +56,9 @@ static int _Cleanup(void *context)
5556static uint32_t _PartitionSize (void * context )
5657{
5758 whFlashH5Ctx * ctx = (whFlashH5Ctx * )context ;
58- if (ctx == NULL ) {
59- return 0U ;
60- }
61- return ctx -> partition_size ;
59+ return (ctx == NULL ) ? 0U : ctx -> partition_size ;
6260}
6361
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- */
7062static int _WriteLock (void * context , uint32_t offset , uint32_t size )
7163{
7264 (void )context ;
@@ -103,7 +95,7 @@ static int _Program(void *context, uint32_t offset, uint32_t size,
10395 const uint8_t * data )
10496{
10597 whFlashH5Ctx * ctx = (whFlashH5Ctx * )context ;
106- int rc ;
98+ uint32_t written = 0U ;
10799
108100 if (ctx == NULL || (size != 0U && data == NULL )) {
109101 return WH_ERROR_BADARGS ;
@@ -114,16 +106,29 @@ static int _Program(void *context, uint32_t offset, uint32_t size,
114106 if (size == 0U ) {
115107 return WH_ERROR_OK ;
116108 }
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 ;
109+
110+ while (written < size ) {
111+ uint32_t in_sector_off = (offset + written ) % WHFH5_SECTOR_SIZE ;
112+ uint32_t sector_base = (offset + written ) - in_sector_off ;
113+ uint32_t chunk = WHFH5_SECTOR_SIZE - in_sector_off ;
114+ if (chunk > size - written ) {
115+ chunk = size - written ;
116+ }
117+
118+ memcpy (cached_sector ,
119+ (const uint8_t * )(ctx -> base + sector_base ),
120+ WHFH5_SECTOR_SIZE );
121+ memcpy (cached_sector + in_sector_off , data + written , chunk );
122+
123+ hal_flash_unlock ();
124+ hal_flash_erase (ctx -> base + sector_base , WHFH5_SECTOR_SIZE );
125+ hal_flash_write (ctx -> base + sector_base , cached_sector ,
126+ WHFH5_SECTOR_SIZE );
127+ hal_flash_lock ();
128+
129+ written += chunk ;
130+ }
131+ return WH_ERROR_OK ;
127132}
128133
129134static int _Erase (void * context , uint32_t offset , uint32_t size )
@@ -171,9 +176,9 @@ static int _Verify(void *context, uint32_t offset, uint32_t size,
171176
172177static int _BlankCheck (void * context , uint32_t offset , uint32_t size )
173178{
174- whFlashH5Ctx * ctx = (whFlashH5Ctx * )context ;
179+ whFlashH5Ctx * ctx = (whFlashH5Ctx * )context ;
175180 const uint8_t * p ;
176- uint32_t i ;
181+ uint32_t i ;
177182
178183 if (ctx == NULL ) {
179184 return WH_ERROR_BADARGS ;
0 commit comments