diff --git a/hal/stm32f4.c b/hal/stm32f4.c index 78084936..96082ffb 100644 --- a/hal/stm32f4.c +++ b/hal/stm32f4.c @@ -196,9 +196,35 @@ void RAMFUNCTION hal_flash_unlock(void) FLASH_KEYR = FLASH_KEY2; } +/* 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. The reset bits are only writable while the corresponding + * cache is disabled, hence the disable/reset/re-enable dance. */ +void RAMFUNCTION hal_cache_invalidate(void) +{ + uint32_t acr = FLASH_ACR; + + if (acr & FLASH_ACR_ENABLE_INST_CACHE) { + FLASH_ACR &= ~FLASH_ACR_ENABLE_INST_CACHE; + FLASH_ACR |= FLASH_ACR_RESET_INST_CACHE; + FLASH_ACR &= ~FLASH_ACR_RESET_INST_CACHE; + FLASH_ACR |= FLASH_ACR_ENABLE_INST_CACHE; + } + if (acr & FLASH_ACR_ENABLE_DATA_CACHE) { + FLASH_ACR &= ~FLASH_ACR_ENABLE_DATA_CACHE; + FLASH_ACR |= FLASH_ACR_RESET_DATA_CACHE; + FLASH_ACR &= ~FLASH_ACR_RESET_DATA_CACHE; + FLASH_ACR |= FLASH_ACR_ENABLE_DATA_CACHE; + } +} + 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(); } diff --git a/hal/stm32g4.c b/hal/stm32g4.c index 08c994b6..137f1436 100644 --- a/hal/stm32g4.c +++ b/hal/stm32g4.c @@ -98,11 +98,37 @@ void RAMFUNCTION hal_flash_unlock(void) } } +/* 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. The reset bits are only writable while the corresponding + * cache is disabled, hence the disable/reset/re-enable dance. */ +void RAMFUNCTION hal_cache_invalidate(void) +{ + uint32_t acr = FLASH_ACR; + + if (acr & FLASH_ACR_ICEN) { + FLASH_ACR &= ~FLASH_ACR_ICEN; + FLASH_ACR |= FLASH_ACR_ICRST; + FLASH_ACR &= ~FLASH_ACR_ICRST; + FLASH_ACR |= FLASH_ACR_ICEN; + } + if (acr & FLASH_ACR_DCEN) { + FLASH_ACR &= ~FLASH_ACR_DCEN; + FLASH_ACR |= FLASH_ACR_DCRST; + FLASH_ACR &= ~FLASH_ACR_DCRST; + FLASH_ACR |= FLASH_ACR_DCEN; + } +} + 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(); } diff --git a/hal/stm32g4.h b/hal/stm32g4.h index 2cec5a8c..2c2e46ba 100644 --- a/hal/stm32g4.h +++ b/hal/stm32g4.h @@ -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). */ diff --git a/src/libwolfboot.c b/src/libwolfboot.c index dca3f523..5569d645 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -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. @@ -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