summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatryk Duda <pdk@semihalf.com>2021-05-27 15:04:18 +0200
committerCommit Bot <commit-bot@chromium.org>2021-06-10 09:18:37 +0000
commita2ffd0f59694e1fa57144fd22f0b32dbb9368440 (patch)
tree956cfb57716ff295536f878b946136d6bb70af6c
parentfa451fa44d7f36c0073c795c9969d8e7f03fd1f3 (diff)
downloadchrome-ec-a2ffd0f59694e1fa57144fd22f0b32dbb9368440.tar.gz
stm32/system: Disable caches before reboot
Affected boards (only STM32H7): - nocturne_fp (dartmonkey) - nucleo-h743zi This fixes problem with jumping to RW when reboot to RO was requested. Log from reproduction on dartmonkey (only relevant parts): --- UART initialized after reboot --- [Image: RO, dartmonkey_v2.0.8961+9a30ce07ee] [Reset cause: reset-pin power-on soft ap-off] ... [1.045743 Jumping to image RW] *** We are in RW. Jump data are initialized and contains correct *** set of reset flags. Reset flags from backup RAM are cleared. reset flags from chip: unknown reset flags from jump data: reset-pin power-on soft sysjump ap-off [1.056198 UART initialized after sysjump] [Image: RW, dartmonkey_v2.0.8961+9a30ce07ee] [Reset cause: reset-pin power-on soft sysjump ap-off] ... > > reboot ro reboot ro Rebooting! *** Now we are in RO. RW saved reset cause in backup RAM (with *** stay-in-ro). Please note that RO also finds jump data and *** report that was sysjump! reset flags from chip: reset-pin power-on soft ap-off stay-in-ro reset flags from jump data: reset-pin power-on soft sysjump ap-off [1.056198 UART initialized after sysjump] [Image: RO, dartmonkey_v2.0.8961+9a30ce07ee] [Reset cause: reset-pin power-on soft sysjump ap-off] When RO is doing sysjump to RW, jump data structure is created in jump_to_image() function. The structure contains information about reset flags. When RW finds jump data in system_common_pre_init() magic field of the structure is set to zero to prevent detecting sysjump accidentally. Nevertheless, when reboot to RO is requested, RO is able to find the structure. As a result, correct reset flags from backup RAM are overwritten by incorrect reset flags from jump data. This happens because we are not flushing D-cache before reboot. All changes in RW which lives in cache (not saved in RAM) will be lost after reboot because cache is always disabled (even if it was previously enabled and we didn't turned it off). To enable cache we need to invalidate it first (see cpu_enable_caches()). Issue reproduces also with debugger connected, except situation when watchpoint is set on jump data magic field. BUG=b:170432597 b:188934337 BRANCH=none TEST=Compile dartmonkey firmware and run it on eg. icetower. In RW, issue 'reboot ro'. Make sure that jump to RO is not performed. TEST=Run flash_write_protect hardware unit test on icetower board using `./test/run_device_tests.py --board dartmonkey \ --tests flash_write_protect` Make sure that after reboot to RO, 'stay-in-ro' reset cause is printed Signed-off-by: Patryk Duda <pdk@semihalf.com> Change-Id: If56153a1a3ac7ae05700eac9ca60e398cf35f182 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2922145 Reviewed-by: Craig Hesling <hesling@chromium.org>
-rw-r--r--chip/stm32/system.c9
-rw-r--r--core/cortex-m/cpu.c6
-rw-r--r--core/cortex-m/cpu.h2
3 files changed, 14 insertions, 3 deletions
diff --git a/chip/stm32/system.c b/chip/stm32/system.c
index 1a9da8c3a4..1f5f9c9108 100644
--- a/chip/stm32/system.c
+++ b/chip/stm32/system.c
@@ -373,6 +373,15 @@ void system_reset(int flags)
chip_save_reset_flags(save_flags);
+#ifdef CONFIG_ARMV7M_CACHE
+ /*
+ * Disable caches (D-cache is also flushed and invalidated)
+ * so changes that lives in cache are saved in memory now.
+ * Any subsequent writes will be done immediately.
+ */
+ cpu_disable_caches();
+#endif
+
if (flags & SYSTEM_RESET_HARD) {
#ifdef CONFIG_SOFTWARE_PANIC
uint32_t reason, info;
diff --git a/core/cortex-m/cpu.c b/core/cortex-m/cpu.c
index 96ac96a016..7c31892c18 100644
--- a/core/cortex-m/cpu.c
+++ b/core/cortex-m/cpu.c
@@ -50,16 +50,16 @@ void cpu_enable_caches(void)
}
}
-static void cpu_sysjump_cache(void)
+void cpu_disable_caches(void)
{
/*
* Disable the I-cache and the D-cache
- * The I-cache will be invalidated after the sysjump if needed
+ * The I-cache will be invalidated after the reboot/sysjump if needed
* (e.g after a flash update).
*/
cpu_clean_invalidate_dcache();
CPU_NVIC_CCR &= ~(CPU_NVIC_CCR_ICACHE | CPU_NVIC_CCR_DCACHE);
asm volatile("dsb; isb");
}
-DECLARE_HOOK(HOOK_SYSJUMP, cpu_sysjump_cache, HOOK_PRIO_LAST);
+DECLARE_HOOK(HOOK_SYSJUMP, cpu_disable_caches, HOOK_PRIO_LAST);
#endif /* CONFIG_ARMV7M_CACHE */
diff --git a/core/cortex-m/cpu.h b/core/cortex-m/cpu.h
index 5f7dd02801..0b03302bfc 100644
--- a/core/cortex-m/cpu.h
+++ b/core/cortex-m/cpu.h
@@ -74,6 +74,8 @@ enum {
void cpu_init(void);
/* Enable the CPU I-cache and D-cache if they are not already enabled */
void cpu_enable_caches(void);
+/* Disable the CPU I-cache and D-cache */
+void cpu_disable_caches(void);
/* Invalidate the D-cache */
void cpu_invalidate_dcache(void);
/* Clean and Invalidate the D-cache to the Point of Coherency */