From 3f84852b4286879f3d25c561b64010344b4632c3 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 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drv/stm32h7-update-server/src/main.rs b/drv/stm32h7-update-server/src/main.rs index ce7a73fea..ba2f8a302 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,24 @@ 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);