From 0f3e837c0ec9557a535b0a316876de6ad70ecdeb Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Fri, 18 Oct 2024 13:04:07 -0400 Subject: [PATCH] Clear SP flash errors we should never see The STM32H7 is haunted/contains an errata where the CPU may speculate into a system area (`0x1ff0_0000`) and trigger a flash error normally only seen when security features are enabled. This is not an official errata but seems to be well(?) reported https://community.st.com/t5/stm32-mcus-products/spurious-rdperr-and-rdserr-when-all-protection-and-security/td-p/279852 https://github.com/zephyrproject-rtos/zephyr/issues/60449 One suggested workaround is to add an extra MPU region which marks The Danger Zone as NX. For the way hubris is designed this isn't plausible. Instead clear any errors before we attempt to write to flash. --- drv/stm32h7-update-server/src/main.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drv/stm32h7-update-server/src/main.rs b/drv/stm32h7-update-server/src/main.rs index ce7a73fea..8106cb983 100644 --- a/drv/stm32h7-update-server/src/main.rs +++ b/drv/stm32h7-update-server/src/main.rs @@ -172,6 +172,7 @@ impl<'a> ServerImpl<'a> { words: &[u32; FLASH_WORD_WORDS], ) -> Result<(), RequestError> { ringbuf_entry!(Trace::WriteStart); + self.clear_errors(); // These variables are _philosophically_ constants, but since they're // generated by taking the address of a linker-generated symbol, we @@ -243,9 +244,21 @@ impl<'a> ServerImpl<'a> { .write(|w| unsafe { w.optkeyr().bits(FLASH_OPT_KEY2) }); } + fn clear_errors(&mut self) { + // https://github.com/zephyrproject-rtos/zephyr/issues/60449 + // https://community.st.com/t5/stm32-mcus-products/spurious-rdperr-and-rdserr-when-all-protection-and-security/td-p/279852 + // There are issue with the CPU speculating into unknown + // areas. One workaround is to explicitly mark the reigon as NX + // via MPU but that's expensive/costs an MPU region + // Another workaround is to just clear errors we don't + // expect to see + self.flash.bank2().ccr.modify(|_, w| { w.clr_rdperr().set_bit().clr_rdserr().set_bit() } ); + } + fn bank_erase(&mut self) -> Result<(), RequestError> { ringbuf_entry!(Trace::EraseStart); + self.clear_errors(); // Enable relevant interrupts for completion (or failure) of erasing // bank2. sys_irq_control(notifications::FLASH_IRQ_MASK, true);