Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions hal/stm32c5.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,13 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
if ((sr & FLASH_SR_ERR_MASK) != 0) {
flash_clear_errors();
FLASH_CR &= ~FLASH_CR_PG;
hal_cache_invalidate();
return -1;
}

FLASH_CR &= ~FLASH_CR_PG;
i += write_len;
DSB();
}
hal_cache_invalidate();
return 0;
}

Expand All @@ -153,6 +151,12 @@ void RAMFUNCTION hal_flash_lock(void)
flash_wait_complete();
if ((FLASH_CR & FLASH_CR_LOCK) == 0)
FLASH_CR |= FLASH_CR_LOCK;
/* Drop the flash read cache at the end of the batch rather than in
* hal_flash_write()/hal_flash_erase(): every write/erase sequence
* ends with a lock, so one invalidate per batch replaces one per
* operation (and per error return), and every consumer is covered,
* not just the ones that remember to ask. */
hal_cache_invalidate();
}

void RAMFUNCTION hal_flash_opt_unlock(void)
Expand Down Expand Up @@ -231,12 +235,10 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
if ((sr & FLASH_SR_ERR_MASK) != 0) {
flash_clear_errors();
FLASH_CR &= ~FLASH_CR_PER;
hal_cache_invalidate();
return -1;
}
}
FLASH_CR &= ~FLASH_CR_PER;
hal_cache_invalidate();
return 0;
}

Expand Down
28 changes: 28 additions & 0 deletions hal/stm32f4.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,37 @@ void RAMFUNCTION hal_flash_unlock(void)
FLASH_KEYR = FLASH_KEY2;
}

#if ((FLASH_ACR_ENABLE_INST_CACHE << 2) != FLASH_ACR_RESET_INST_CACHE) || \
((FLASH_ACR_ENABLE_DATA_CACHE << 2) != FLASH_ACR_RESET_DATA_CACHE)
#error "STM32F4: flash cache reset bits are not two positions above the enables"
#endif
/* RM0090 3.5.1: the instruction and data caches keep lines fetched before an
* erase/program, so a read-back through the flash memory map can return
* pre-erase bytes. A cache reset bit is only writable while its cache is
* disabled, and the reset bits sit two positions above the enable bits
* (ICEN 9 -> ICRST 11, DCEN 10 -> DCRST 12), so one shift covers both. */
void RAMFUNCTION hal_cache_invalidate(void)
{
uint32_t acr = FLASH_ACR;
uint32_t en = acr & (FLASH_ACR_ENABLE_INST_CACHE |
FLASH_ACR_ENABLE_DATA_CACHE);
uint32_t off = acr & ~en;

if (en == 0)
return;
FLASH_ACR = off; /* disable the caches that were on */
FLASH_ACR = off | (en << 2); /* set their reset bits */
FLASH_ACR = off; /* release reset */
FLASH_ACR = acr; /* restore the original enables */
}

void RAMFUNCTION hal_flash_lock(void)
{
FLASH_CR |= FLASH_CR_LOCK;
/* Drop the stale cache lines at the end of the write/erase batch: every
* sequence in wolfBoot ends with a lock, so one invalidate per batch
* covers every consumer that reads flash back. */
hal_cache_invalidate();
}


Expand Down
27 changes: 27 additions & 0 deletions hal/stm32g4.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,38 @@ void RAMFUNCTION hal_flash_unlock(void)
}
}

#if ((FLASH_ACR_ICEN << 2) != FLASH_ACR_ICRST) || \
((FLASH_ACR_DCEN << 2) != FLASH_ACR_DCRST)
#error "STM32G4: flash cache reset bits are not two positions above the enables"
#endif
/* RM0440 3.3.3: the instruction and data caches keep lines fetched before an
* erase/program, so a read-back through the flash memory map can return
* pre-erase bytes. A cache reset bit is only writable while its cache is
* disabled, and the reset bits sit two positions above the enable bits
* (ICEN 9 -> ICRST 11, DCEN 10 -> DCRST 12), so one shift covers both. */
void RAMFUNCTION hal_cache_invalidate(void)
{
uint32_t acr = FLASH_ACR;
uint32_t en = acr & (FLASH_ACR_ICEN | FLASH_ACR_DCEN);
uint32_t off = acr & ~en;

if (en == 0)
return;
FLASH_ACR = off; /* disable the caches that were on */
FLASH_ACR = off | (en << 2); /* set their reset bits */
FLASH_ACR = off; /* release reset */
FLASH_ACR = acr; /* restore the original enables */
}

void RAMFUNCTION hal_flash_lock(void)
{
flash_wait_complete();
if ((FLASH_CR & FLASH_CR_LOCK) == 0)
FLASH_CR |= FLASH_CR_LOCK;
/* Drop the stale cache lines at the end of the write/erase batch: every
* sequence in wolfBoot ends with a lock, so one invalidate per batch
* covers every consumer that reads flash back. */
hal_cache_invalidate();
}


Expand Down
2 changes: 2 additions & 0 deletions hal/stm32g4.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@
#define FLASH_ACR_PRFTEN (1 << 8)
#define FLASH_ACR_ICEN (1 << 9)
#define FLASH_ACR_DCEN (1 << 10)
#define FLASH_ACR_ICRST (1 << 11)
#define FLASH_ACR_DCRST (1 << 12)
#define FLASH_ACR_LATENCY_4WS (0x4)

/* G4 has a single BSY at bit 16 (no BSY1/BSY2 like G0). */
Expand Down
8 changes: 6 additions & 2 deletions hal/stm32u3.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
FLASH_NS_CR &= ~FLASH_CR_PG;
i += 8;
}
hal_cache_invalidate();
return 0;
}

Expand All @@ -128,6 +127,12 @@ void RAMFUNCTION hal_flash_lock(void)
flash_wait_complete();
if ((FLASH_NS_CR & FLASH_CR_LOCK) == 0)
FLASH_NS_CR |= FLASH_CR_LOCK;
/* Drop the flash read cache at the end of the batch rather than in
* hal_flash_write()/hal_flash_erase(): every write/erase sequence
* ends with a lock, so one invalidate per batch replaces one per
* operation (and per error return), and every consumer is covered,
* not just the ones that remember to ask. */
hal_cache_invalidate();
}

void RAMFUNCTION hal_flash_opt_unlock(void)
Expand Down Expand Up @@ -194,7 +199,6 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
flash_wait_complete();
}
FLASH_NS_CR &= ~FLASH_CR_PER;
hal_cache_invalidate();
return 0;
}

Expand Down
8 changes: 7 additions & 1 deletion hal/stm32u5.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ void RAMFUNCTION hal_flash_lock(void)
#endif
if ((FLASH_NS_CR & FLASH_CR_LOCK) == 0)
FLASH_NS_CR |= FLASH_CR_LOCK;
/* Drop the flash read cache at the end of the batch rather than in
* hal_flash_write()/hal_flash_erase(): every write/erase sequence
* ends with a lock, so one invalidate per batch replaces one per
* operation (and per error return), and every consumer is covered,
* not just the ones that remember to ask. */
hal_cache_invalidate();
}

void RAMFUNCTION hal_flash_opt_unlock(void)
Expand Down Expand Up @@ -619,7 +625,7 @@ void hal_cache_disable(void)
ICACHE_CR &= ~ICACHE_CR_CEN;
}

void hal_cache_invalidate(void)
void RAMFUNCTION hal_cache_invalidate(void)
{
/* only try and invalidate cache if enabled */
if ((ICACHE_CR & ICACHE_CR_CEN) == 0)
Expand Down
14 changes: 14 additions & 0 deletions include/hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@ uint64_t hal_get_timer_us(void);
#endif
void hal_flash_unlock(void);
void hal_flash_lock(void);
/*
* Drop any CPU-side cache of flash contents.
*
* On parts where flash reads are cached (e.g. the STM32 ICACHE), the CPU can
* still see pre-erase bytes after hal_flash_write()/hal_flash_erase() have
* completed. Any code that writes flash and then reads it back through the
* memory map must call this in between.
*
* src/libwolfboot.c provides a weak no-op, so targets without such a cache
* need not implement it; a HAL that has one overrides it and must also call
* it from its own hal_flash_lock(), which is where every write/erase batch
* ends.
*/
void hal_cache_invalidate(void);
/*
* Lock the flash region [address, address + len) against writes.
* Return 0 on success, or a negative value on failure.
Expand Down
6 changes: 6 additions & 0 deletions include/wolfboot/wcs_pkcs11.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,5 +343,11 @@ CK_RV CSME_NSE_API C_GetFunctionStatus_nsc_call(CK_SESSION_HANDLE hSession);
CK_RV CSME_NSE_API C_CancelFunction_nsc_call(CK_SESSION_HANDLE hSession);
CK_RV CSME_NSE_API C_WaitForSlotEvent_nsc_call(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved);

#ifdef PKCS11_STORE_STATS
CK_RV CSME_NSE_API C_StoreGetStats_nsc_call(uint32_t *pCommits,
uint32_t *pErases, uint32_t *pPrograms);
CK_RV CSME_NSE_API C_StoreResetStats_nsc_call(void);
#endif

#endif /* SECURE_PKCS11 */
#endif /* !WOLFBOOT_PKCS11_H */
4 changes: 4 additions & 0 deletions options.mk
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,10 @@ ifeq ($(WOLFBOOT_DICE_HW),1)
endif
endif

ifeq ($(PKCS11_STORE_STATS),1)
CFLAGS+=-DPKCS11_STORE_STATS
endif

ifeq ($(WOLFCRYPT_TZ_PKCS11),1)
CFLAGS+=-DSECURE_PKCS11
CFLAGS+=-DWOLFPKCS11_USER_SETTINGS
Expand Down
12 changes: 8 additions & 4 deletions src/libwolfboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,14 @@ static const uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL;
#define FLAGS_UPDATE_EXT() PARTN_IS_EXT(PART_UPDATE)
#endif

/* Weak no-op default: targets whose flash reads are not cached need not
* implement this. It lives outside NVM_FLASH_WRITEONCE because callers such
* as src/pkcs11_store.c are built independently of that option. */
void WEAKFUNCTION hal_cache_invalidate(void)
{
/* if cache flushing is required implement in hal */
}

#ifdef NVM_FLASH_WRITEONCE
/* Some internal FLASH memory models don't allow
* multiple writes after erase in the same page/area.
Expand Down Expand Up @@ -282,10 +290,6 @@ static uint8_t get_base_offset(uint8_t *base, uintptr_t off)
return *(uint8_t*)((uintptr_t)base - off); /* ignore array bounds error */
}

void WEAKFUNCTION hal_cache_invalidate(void)
{
/* if cache flushing is required implement in hal */
}
#ifdef __CCRX__
#pragma section FRAM
#endif
Expand Down
24 changes: 24 additions & 0 deletions src/pkcs11_callable.c
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,30 @@ CK_RV CSME_NSE_API C_CancelFunction_nsc_call(CK_SESSION_HANDLE hSession)
return C_CancelFunction(hSession);
}

#ifdef PKCS11_STORE_STATS
/* Flash-activity counters, implemented in src/pkcs11_store.c (the wolfBoot
* store backend); declared here to keep the wolfPKCS11 submodule untouched. */
void wolfPKCS11_Store_GetStats(uint32_t *commits, uint32_t *erases,
uint32_t *programs);
void wolfPKCS11_Store_ResetStats(void);

CK_RV CSME_NSE_API C_StoreGetStats_nsc_call(uint32_t *pCommits,
uint32_t *pErases, uint32_t *pPrograms)
{
NSC_CHK(ns_ok(pCommits, sizeof(uint32_t)));
NSC_CHK(ns_ok(pErases, sizeof(uint32_t)));
NSC_CHK(ns_ok(pPrograms, sizeof(uint32_t)));
wolfPKCS11_Store_GetStats(pCommits, pErases, pPrograms);
return CKR_OK;
}

CK_RV CSME_NSE_API C_StoreResetStats_nsc_call(void)
{
wolfPKCS11_Store_ResetStats();
return CKR_OK;
}
#endif

CK_RV CSME_NSE_API C_WaitForSlotEvent_nsc_call(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
{
/* pReserved must be NULL; the underlying call rejects anything else. */
Expand Down
Loading
Loading