diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader
index 866f3ad1b9..6c5bee2c63 100644
--- a/core/SConscript.bootloader
+++ b/core/SConscript.bootloader
@@ -24,6 +24,7 @@ FEATURES_WANTED = [
"secure_domain",
"tropic",
"usb",
+ "iwdg",
]
if TREZOR_MODEL in ('T3W1', ):
diff --git a/core/embed/sec/iwdg/inc/sec/iwdg.h b/core/embed/sec/iwdg/inc/sec/iwdg.h
new file mode 100644
index 0000000000..d4d3942454
--- /dev/null
+++ b/core/embed/sec/iwdg/inc/sec/iwdg.h
@@ -0,0 +1,37 @@
+/*
+ * 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 .
+ */
+
+#pragma once
+
+#include
+
+#define IWDG_MAX_TIME (60 * 60 * 4) // 4 hours
+
+/**
+ * @brief Start the Independent Watchdog, to enforce reset after specified time
+ * elapsed.
+ *
+ * The IWDG is clocked from LSI, which is expected to be set to 250 Hz.
+ * The IWDG prescaler is set to 1024, which means that the watchdog
+ * will tick every 4.096 s. The time is floored to the nearest multiple of 4.096
+ * s.
+ *
+ * @param time_s Watchdog timeout in seconds. Time is ceiled to IWDG_MAX_TIME.
+ */
+void iwdg_start(uint32_t time_s);
diff --git a/core/embed/sec/iwdg/stm32/iwdg.c b/core/embed/sec/iwdg/stm32/iwdg.c
new file mode 100644
index 0000000000..c4d69e442d
--- /dev/null
+++ b/core/embed/sec/iwdg/stm32/iwdg.c
@@ -0,0 +1,49 @@
+/*
+ * 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 .
+ */
+#ifdef SECURE_MODE
+
+#include
+#include
+
+#include
+
+_Static_assert(LSI_VALUE == 250, "LSI_VALUE must be defined to 250 Hz");
+
+void iwdg_start(uint32_t time_s) {
+ if (time_s > IWDG_MAX_TIME) {
+ // Limit the maximum watchdog timeout to 4 hours
+ time_s = IWDG_MAX_TIME;
+ }
+
+ // Set the reload value based on the desired time in seconds
+ uint32_t reload_value = ((time_s * LSI_VALUE) / 1024) - 1;
+
+ IWDG_HandleTypeDef hiwdg = {0};
+
+ hiwdg.Instance = IWDG;
+ hiwdg.Init.Prescaler = IWDG_PRESCALER_1024;
+ hiwdg.Init.Reload = reload_value;
+ hiwdg.Init.Window = 0xFFF;
+ hiwdg.Init.EWI = 0;
+
+ // Configure the IWDG
+ HAL_IWDG_Init(&hiwdg);
+}
+
+#endif
diff --git a/core/embed/sys/bsp/stm32u5/stm32u5xx_hal_conf.h b/core/embed/sys/bsp/stm32u5/stm32u5xx_hal_conf.h
index f213c6446e..0d98c93979 100644
--- a/core/embed/sys/bsp/stm32u5/stm32u5xx_hal_conf.h
+++ b/core/embed/sys/bsp/stm32u5/stm32u5xx_hal_conf.h
@@ -60,7 +60,7 @@ extern "C" {
#define HAL_HASH_MODULE_ENABLED
/*#define HAL_HRTIM_MODULE_ENABLED */
/*#define HAL_IRDA_MODULE_ENABLED */
-/*#define HAL_IWDG_MODULE_ENABLED */
+#define HAL_IWDG_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
/*#define HAL_I2S_MODULE_ENABLED */
#define HAL_LPTIM_MODULE_ENABLED
diff --git a/core/embed/sys/startup/stm32u5/startup_init.c b/core/embed/sys/startup/stm32u5/startup_init.c
index 1233fc8b43..9fc66a5b9f 100644
--- a/core/embed/sys/startup/stm32u5/startup_init.c
+++ b/core/embed/sys/startup/stm32u5/startup_init.c
@@ -91,7 +91,15 @@ void lsi_init(void) {
uint32_t bdcr_temp = RCC->BDCR;
- if (RCC_LSI_DIV1 != (bdcr_temp & RCC_BDCR_LSIPREDIV)) {
+#if LSI_VALUE == 32000
+ uint32_t lsi_div = RCC_LSI_DIV1;
+#elif LSI_VALUE == 250
+ uint32_t lsi_div = RCC_LSI_DIV128;
+#else
+#error Unsupported LSI frequency
+#endif
+
+ if (lsi_div != (bdcr_temp & RCC_BDCR_LSIPREDIV)) {
if (((bdcr_temp & RCC_BDCR_LSIRDY) == RCC_BDCR_LSIRDY) &&
((bdcr_temp & RCC_BDCR_LSION) != RCC_BDCR_LSION)) {
// If LSIRDY is set while LSION is not enabled, LSIPREDIV can't be updated
@@ -110,7 +118,7 @@ void lsi_init(void) {
}
// Set LSI division factor
- MODIFY_REG(RCC->BDCR, RCC_BDCR_LSIPREDIV, 0);
+ MODIFY_REG(RCC->BDCR, RCC_BDCR_LSIPREDIV, lsi_div);
}
// Enable the Internal Low Speed oscillator (LSI)
@@ -254,7 +262,9 @@ void SystemInit(void) {
#ifdef USE_LSE
lse_init();
-#else
+#endif
+
+#if defined(USE_LSI) || !defined(USE_LSE)
lsi_init();
#endif
diff --git a/core/embed/sys/trustzone/stm32u5/trustzone.c b/core/embed/sys/trustzone/stm32u5/trustzone.c
index f8457e969c..c1b1406018 100644
--- a/core/embed/sys/trustzone/stm32u5/trustzone.c
+++ b/core/embed/sys/trustzone/stm32u5/trustzone.c
@@ -517,6 +517,10 @@ void tz_init(void) {
HAL_GTZC_TZSC_ConfigPeriphAttributes(
GTZC_PERIPH_SAES, GTZC_TZSC_PERIPH_SEC | GTZC_TZSC_PERIPH_PRIV);
+ // Set IWDG as secure & privileged
+ HAL_GTZC_TZSC_ConfigPeriphAttributes(
+ GTZC_PERIPH_IWDG, GTZC_TZSC_PERIPH_SEC | GTZC_TZSC_PERIPH_PRIV);
+
// Set all interrupts as non-secure
for (int i = 0; i < 512; i++) {
NVIC_SetTargetState(i);