refactor(core): remove cyclic depenendency - ensure display compatibility
What changed, and why it matters
This is a code cleanup change in Trezor's embedded firmware. It moves display de-initialization logic into a new compatibility helper file and renames a clock-setting function to make the code clearer. There is no direct evidence in the commit that this fixes an active security vulnerability; it appears to be a refactoring to remove a circular dependency between system startup code and the display driver.
Treat as a routine refactoring commit. Reviewers may want to confirm that display_deinit() is still invoked exactly once in each handover path and that the new compatibility.c is included in all relevant STM32F4 model builds, which the build script changes appear to do.
Security signals we found
Refactoring of bootloader/firmware handover compatibility code
Display deinitialization moved to a dedicated compatibility module
No functional change to the deinitialization sequence
No changelog entry and no security advisory language in commit message
Evidence from the diff
The commit refactors STM32F4 display handover logic. A new file, core/embed/io/display/stm32f4/compatibility.c, introduces ensure_compatible_display_settings_for_bootloader() and ensure_compatible_display_settings(), both wrapping display_deinit() with appropriate flags. The bootutils.c calls are updated to use these helpers, and ensure_compatible_settings() in sysutils.c is renamed to ensure_compatible_core_clock(). Build scripts for D001, T2B1, and T2T1 models add the new compatibility.c source. The behavior is functionally equivalent: display deinit and core-clock adjustment still occur before jumping to bootloader or next firmware stage.
Changed components
core/embed/io/display/stm32f4/compatibility.ccore/embed/sys/startup/stm32/bootutils.ccore/embed/sys/startup/stm32/sysutils.ccore/embed/sys/startup/inc/sys/bootutils.hcore/embed/sys/startup/inc/sys/sysutils.hcore/site_scons/models/D001/discovery.pycore/site_scons/models/T2B1/trezor_r_v10.pycore/site_scons/models/T2T1/trezor_t.pyInspect captured patch +69 / −16
diff --git a/core/embed/io/display/stm32f4/compatibility.c b/core/embed/io/display/stm32f4/compatibility.c
new file mode 100644
index 00000000..b4db7001
--- /dev/null
+++ b/core/embed/io/display/stm32f4/compatibility.c
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef KERNEL_MODE
+
+#include <trezor_bsp.h>
+#include <trezor_model.h>
+
+#include <io/display.h>
+#include <sys/bootutils.h>
+
+void ensure_compatible_display_settings_for_bootloader(void) {
+ // We are going to jump directly to the bootloader, so we need to
+ // ensure that the device is in a compatible state. Following lines
+ // ensure the display is properly deinitialized, CPU frequency is
+ // properly set and we are running in privileged thread mode.
+ display_deinit(DISPLAY_RESET_CONTENT);
+}
+
+void ensure_compatible_display_settings(void) {
+ // Ensure the display is properly deinitialized, CPU frequency is
+ // properly set. It's needed for backward compatibility with the older
+ // firmware.
+ display_deinit(DISPLAY_JUMP_BEHAVIOR);
+}
+
+#endif // KERNEL_MODE
diff --git a/core/embed/sys/startup/inc/sys/bootutils.h b/core/embed/sys/startup/inc/sys/bootutils.h
index 9d523026..752aac2b 100644
--- a/core/embed/sys/startup/inc/sys/bootutils.h
+++ b/core/embed/sys/startup/inc/sys/bootutils.h
@@ -93,3 +93,13 @@ void __attribute__((noreturn)) reboot_or_halt_after_rsod(void);
// memory and registers that could contain sensitive information.
void __attribute__((noreturn)) jump_to_next_stage(uint32_t vectbl_address,
const startup_args_t *args);
+
+// Ensures the device is in a compatible state before jumping to the next stage.
+// This function is used to ensure backward compatibility with older versions of
+// released bootloaders and firmware. Implementation is platform dependand.
+void ensure_compatible_display_settings_for_bootloader(void);
+
+// Ensures the device is in a compatible state before jumping to to kernel.
+// This function is used to ensure backward compatibility with older versions of
+// released bootloaders and firmware. Implementation is platform dependand.
+void ensure_compatible_display_settings(void);
diff --git a/core/embed/sys/startup/inc/sys/sysutils.h b/core/embed/sys/startup/inc/sys/sysutils.h
index d79f8bca..45b9c3fb 100644
--- a/core/embed/sys/startup/inc/sys/sysutils.h
+++ b/core/embed/sys/startup/inc/sys/sysutils.h
@@ -48,13 +48,13 @@ __attribute((noreturn)) void call_with_new_stack(uint32_t arg1, uint32_t arg2,
// error_handler callback that draws an RSOD screen.
void ensure_thread_mode(void);
-// Ensure compatible hardware settings before jumping to
+// Ensure compatible core clock settings before jumping to
// the different booting stage. This function is used to
// ensure backward compatibility with older versions of
// released bootloaders and firmware.
//
// Does nothing on almost all platforms.
-void ensure_compatible_settings(void);
+void ensure_compatible_core_clock(void);
// Clears USB peripheral fifo memory
//
diff --git a/core/embed/sys/startup/stm32/bootutils.c b/core/embed/sys/startup/stm32/bootutils.c
index c55aa8c9..a6cfc234 100644
--- a/core/embed/sys/startup/stm32/bootutils.c
+++ b/core/embed/sys/startup/stm32/bootutils.c
@@ -32,10 +32,6 @@
#include <sys/systick.h>
#include <sys/sysutils.h>
-#ifdef STM32F4
-#include <io/display.h>
-#endif
-
// Battery powered devices (USE_POWER_MANAGER) should not stall
// after showing RSOD, as it would drain the battery.
#ifdef USE_POWER_MANAGER
@@ -190,11 +186,10 @@ __attribute__((noreturn)) static void reboot_with_args(boot_command_t command,
#ifdef STM32F4
// We are going to jump directly to the bootloader, so we need to
- // ensure that the device is in a compatible state. Following lines
- // ensure the display is properly deinitialized, CPU frequency is
- // properly set and we are running in privileged thread mode.
- display_deinit(DISPLAY_RESET_CONTENT);
- ensure_compatible_settings();
+ // ensure that the device is in a compatible state.
+ ensure_compatible_display_settings_for_bootloader();
+ ensure_compatible_core_clock();
+ // Ensure the device is running in privileged thread mode.
ensure_thread_mode();
#endif
@@ -274,10 +269,10 @@ void __attribute__((noreturn)) jump_to_next_stage(uint32_t vectbl_address,
const startup_args_t* args) {
#ifdef STM32F4
// Ensure the display is properly deinitialized, CPU frequency is
- // properly set. It's needed for backward compatibility with the older
+ // properly set. This is needed for backward compatibility with the older
// firmware.
- display_deinit(DISPLAY_JUMP_BEHAVIOR);
- ensure_compatible_settings();
+ ensure_compatible_display_settings();
+ ensure_compatible_core_clock();
#endif
// Disable interrupts, MPU, clear all registers and set up a new stack
diff --git a/core/embed/sys/startup/stm32/sysutils.c b/core/embed/sys/startup/stm32/sysutils.c
index 9c732ee4..324f2a79 100644
--- a/core/embed/sys/startup/stm32/sysutils.c
+++ b/core/embed/sys/startup/stm32/sysutils.c
@@ -219,7 +219,7 @@ __attribute((used)) void clear_otg_hs_memory(void) {
#endif
}
-void ensure_compatible_settings(void) {
+void ensure_compatible_core_clock(void) {
#ifdef TREZOR_MODEL_T2T1
// Early version of bootloader on T2T1 expects 168 MHz core clock.
// So we need to set it here before handover to the bootloader.
diff --git a/core/site_scons/models/D001/discovery.py b/core/site_scons/models/D001/discovery.py
index 813948dd..3e19cf51 100644
--- a/core/site_scons/models/D001/discovery.py
+++ b/core/site_scons/models/D001/discovery.py
@@ -47,6 +47,7 @@ def configure(
if "display" in features_wanted:
sources += [
+ "embed/io/display/stm32f4/compatibility.c",
"embed/io/display/stm32f429i-disc1/display_driver.c",
"embed/io/display/stm32f429i-disc1/display_ltdc.c",
"embed/io/display/stm32f429i-disc1/ili9341_spi.c",
diff --git a/core/site_scons/models/T2B1/trezor_r_v10.py b/core/site_scons/models/T2B1/trezor_r_v10.py
index 945b4f1e..ddad65a6 100644
--- a/core/site_scons/models/T2B1/trezor_r_v10.py
+++ b/core/site_scons/models/T2B1/trezor_r_v10.py
@@ -59,7 +59,10 @@ def configure(
defines += [("USE_SECRET_KEYS", "1")]
if "display" in features_wanted:
- sources += ["embed/io/display/vg-2864/display_driver.c"]
+ sources += [
+ "embed/io/display/stm32f4/compatibility.c",
+ "embed/io/display/vg-2864/display_driver.c",
+ ]
paths += ["embed/io/display/inc"]
defines += [("USE_DISPLAY", "1")]
diff --git a/core/site_scons/models/T2T1/trezor_t.py b/core/site_scons/models/T2T1/trezor_t.py
index c56b2b70..eb64ded9 100644
--- a/core/site_scons/models/T2T1/trezor_t.py
+++ b/core/site_scons/models/T2T1/trezor_t.py
@@ -54,6 +54,7 @@ def configure(
defines += [("USE_SECRET_KEYS", "1")]
if "display" in features_wanted:
+ sources += ["embed/io/display/stm32f4/compatibility.c"]
sources += ["embed/io/display/st-7789/display_nofb.c"]
sources += ["embed/io/display/st-7789/display_driver.c"]
sources += ["embed/io/display/st-7789/display_io.c"]
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.