diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c
index 0051b7ddfa..04c8469778 100644
--- a/core/embed/firmware/main.c
+++ b/core/embed/firmware/main.c
@@ -87,6 +87,9 @@
#ifdef USE_SECP256K1_ZKP
#include "zkp_context.h"
#endif
+#if USE_TAMPERS
+#include "tamper.h"
+#endif
// from util.s
extern void shutdown_privileged(void);
@@ -165,6 +168,10 @@ int main(void) {
touch_init();
#endif
+#if USE_TAMPERS
+ tamper_init();
+#endif
+
#ifdef USE_SD_CARD
sdcard_init();
#endif
diff --git a/core/embed/trezorhal/stm32f4/irq.h b/core/embed/trezorhal/stm32f4/irq.h
index 1d06d4f958..319755f1c5 100644
--- a/core/embed/trezorhal/stm32f4/irq.h
+++ b/core/embed/trezorhal/stm32f4/irq.h
@@ -160,4 +160,7 @@ static inline void restore_irq_pri(uint32_t state) {
#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
#define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
+// !@# TAMPER interrupt priority should be probably much higher
+#define IRQ_PRI_TAMP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
+
#endif // MICROPY_INCLUDED_STM32_IRQ_H
diff --git a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h
index 325d229bdb..f619bcca57 100644
--- a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h
+++ b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h
@@ -69,7 +69,7 @@ extern "C" {
/*#define HAL_PKA_MODULE_ENABLED */
/*#define HAL_QSPI_MODULE_ENABLED */
/*#define HAL_RNG_MODULE_ENABLED */
-/*#define HAL_RTC_MODULE_ENABLED */
+#define HAL_RTC_MODULE_ENABLED
/*#define HAL_SAI_MODULE_ENABLED */
/*#define HAL_CRYP_MODULE_ENABLED */
/*#define HAL_SD_MODULE_ENABLED */
diff --git a/core/embed/trezorhal/stm32u5/tamper.c b/core/embed/trezorhal/stm32u5/tamper.c
new file mode 100644
index 0000000000..fd4b9d18c8
--- /dev/null
+++ b/core/embed/trezorhal/stm32u5/tamper.c
@@ -0,0 +1,201 @@
+/*
+ * 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 .
+ */
+
+#include
+#include
+#include
+#include STM32_HAL_H
+
+// Fixes a typo in CMSIS Device library for STM32U5
+#undef TAMP_CR3_ITAMP7NOER_Msk
+#undef TAMP_CR3_ITAMP7NOER
+#define TAMP_CR3_ITAMP7NOER_Msk (0x1UL << TAMP_CR3_ITAMP7NOER_Pos)
+#define TAMP_CR3_ITAMP7NOER TAMP_CR3_ITAMP7NOER_Msk
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// Temporary solution for STM32U5A9 Discovery Board experiments
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+void tamper_init() {
+ RCC_PeriphCLKInitTypeDef clk_init_def = {0};
+ RCC_OscInitTypeDef osc_init_def = {0};
+
+ // Enable LSI clock
+ osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_LSI;
+ osc_init_def.LSIState = RCC_LSI_ON;
+ HAL_RCC_OscConfig(&osc_init_def);
+
+ // Select RTC peripheral clock source
+ clk_init_def.PeriphClockSelection = RCC_PERIPHCLK_RTC;
+ clk_init_def.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
+ HAL_RCCEx_PeriphCLKConfig(&clk_init_def);
+
+ // Enable RTC peripheral (tampers are part of it)
+ __HAL_RCC_RTC_ENABLE();
+ __HAL_RCC_RTCAPB_CLK_ENABLE();
+
+ // Clear all pending interrupts
+ // They may be some as RTC/TAMP peripherals resides inside the
+ // backup voltage domain
+ TAMP->SCR = TAMP_SCR_CTAMP2F | TAMP_SCR_CITAMP1F | TAMP_SCR_CITAMP2F |
+ TAMP_SCR_CITAMP3F | TAMP_SCR_CITAMP5F | TAMP_SCR_CITAMP6F |
+ TAMP_SCR_CITAMP7F | TAMP_SCR_CITAMP8F | TAMP_SCR_CITAMP9F |
+ TAMP_SCR_CITAMP11F | TAMP_SCR_CITAMP12F | TAMP_SCR_CITAMP13F;
+
+ NVIC_ClearPendingIRQ(TAMP_IRQn);
+
+ // Enable battery and power monitoring (!@# rework it)
+ RCC->AHB3ENR |= RCC_AHB3ENR_PWREN;
+ // HAL_PWR_EnableBkUpAccess();
+ HAL_PWREx_EnableMonitoring();
+ // HAL_PWR_DisableBkUpAccess();
+
+ // Enable all internal tampers (4th and 10th are intentionally skipped)
+ // Enable TAMP_IN2 external input (PA0)
+ // We select all of them despite some of them are never triggered
+ TAMP->CR1 =
+ TAMP_CR1_TAMP2E | // external TAMP_IN2
+ TAMP_CR1_ITAMP1E | // backup domain voltage monitoring
+ TAMP_CR1_ITAMP2E | // temperature monitoring
+ TAMP_CR1_ITAMP3E | // LSE monitoring (LSECSS)
+ TAMP_CR1_ITAMP5E | // RTC calendar overflow
+ TAMP_CR1_ITAMP6E | // JTAG/SWD access when RDP > 0
+ TAMP_CR1_ITAMP7E | // ADC4 analog watchdog monitoring 1
+ TAMP_CR1_ITAMP8E | // Monotonic counter 1 overflow
+ TAMP_CR1_ITAMP9E | // Crypto periherals fault (SAES, AES, PKA, TRNG)
+ TAMP_CR1_ITAMP11E | // IWDG reset when tamper flag is set
+ TAMP_CR1_ITAMP12E | // ADC4 analog watchdog monitoring 2
+ TAMP_CR1_ITAMP13E; // ADC4 analog watchdog monitoring 3
+
+ // Switch all internal tampers to the "confirmed" mode
+ // => all secrets all deleted when any tamper event is triggered
+ TAMP->CR3 = 0;
+
+ // Setup external tampers
+ // TAMP_IN2 active low, "confirmed" mode
+ TAMP->CR2 = 0;
+ // TAMP_CR2_TAMP2TRG;
+
+ // Set external tamper input filter
+ TAMP->FLTCR =
+ // TAMP_FLTCR_TAMPPUDIS | // disable pre-charge of TAMP_INx pins
+ (3 << TAMP_FLTCR_TAMPPRCH_Pos) | // pre-charge 8 RTCCLK cycles
+ (2 << TAMP_FLTCR_TAMPFLT_Pos) | // activated after 4 same samples
+ (7 << TAMP_FLTCR_TAMPFREQ_Pos); // sampling period RTCCLK / 256 (128Hz)
+
+ // Enable all interrupts for all internal tampers
+ TAMP->IER = TAMP_IER_TAMP2IE | TAMP_IER_ITAMP1IE | TAMP_IER_ITAMP2IE |
+ TAMP_IER_ITAMP3IE | TAMP_IER_ITAMP5IE | TAMP_IER_ITAMP6IE |
+ TAMP_IER_ITAMP7IE | TAMP_IER_ITAMP8IE | TAMP_IER_ITAMP9IE |
+ TAMP_IER_ITAMP11IE | TAMP_IER_ITAMP12IE | TAMP_IER_ITAMP13IE;
+
+ // Enable TAMP interrupt at NVIC controller
+ NVIC_SetPriority(TAMP_IRQn, IRQ_PRI_TAMP);
+ NVIC_EnableIRQ(TAMP_IRQn);
+
+ // svc_setpriority(TAMP_IRQn, IRQ_PRI_TAMP);
+ // svc_enableIRQ(TAMP_IRQn);
+}
+
+// Interrupt handle for all tamper events
+// It displays an error message
+void TAMP_IRQHandler(void) {
+ const char* reason = "UNKNOWN";
+
+ uint32_t sr = TAMP->SR;
+
+ if (sr & TAMP_SR_TAMP1F) {
+ reason = "INPUT1";
+ } else if (sr & TAMP_SR_TAMP2F) {
+ reason = "INPUT2";
+ } else if (sr & TAMP_SR_ITAMP1F) {
+ reason = "VOLTAGE";
+ } else if (sr & TAMP_SR_ITAMP2F) {
+ reason = "TEMPERATURE";
+ } else if (sr & TAMP_SR_ITAMP3F) {
+ reason = "LSE CLOCK";
+ } else if (sr & TAMP_SR_ITAMP5F) {
+ reason = "RTC OVERFLOW";
+ } else if (sr & TAMP_SR_ITAMP6F) {
+ reason = "SWD ACCESS";
+ } else if (sr & TAMP_SR_ITAMP7F) {
+ reason = "ANALOG WDG1";
+ } else if (sr & TAMP_SR_ITAMP8F) {
+ reason = "MONO COUNTER";
+ } else if (sr & TAMP_SR_ITAMP9F) {
+ reason = "CRYPTO ERROR";
+ } else if (sr & TAMP_SR_ITAMP11F) {
+ reason = "IWDG";
+ } else if (sr & TAMP_SR_ITAMP12F) {
+ reason = "ANALOG WDG2";
+ } else if (sr & TAMP_SR_ITAMP13F) {
+ reason = "ANALOG WDG3";
+ }
+
+ error_shutdown("INTERNAL TAMPER", reason);
+}
+
+// Triggers ITAMP5 by overflowing RTC date/time
+static void tamper_test_rtc_overflow(void) {
+ RTC_HandleTypeDef hrtc;
+ RTC_DateTypeDef date = {0};
+ RTC_TimeTypeDef time = {0};
+
+ // Initialize RTC and select BCD format for date & time
+ hrtc.Instance = RTC;
+ hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
+ hrtc.Init.AsynchPrediv = 127;
+ hrtc.Init.SynchPrediv = 255;
+ hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
+ hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
+ hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
+ hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
+ hrtc.Init.OutPutPullUp = RTC_OUTPUT_PULLUP_NONE;
+ hrtc.Init.BinMode = RTC_BINARY_NONE;
+ HAL_RTC_Init(&hrtc);
+
+ // set date 99/12/31
+ date.Year = 0x99;
+ date.Month = 0x12;
+ date.Date = 0x31;
+ date.WeekDay = 0x00;
+ HAL_RTC_SetDate(&hrtc, &date, RTC_FORMAT_BCD);
+
+ // set time 23:59:50
+ time.Hours = 0x23;
+ time.Minutes = 0x59;
+ time.Seconds = 0x50;
+ HAL_RTC_SetTime(&hrtc, &time, RTC_FORMAT_BCD);
+}
+
+// Triggers ITAMP8 by overflowing monotonic counter
+static void tamper_test_counter_overflow(void) {
+ for (uint32_t i = 0; i < UINT32_MAX; i++) {
+ TAMP->COUNTR = 0;
+ }
+ TAMP->COUNTR = 0;
+}
+
+void tamper_test(uint32_t tamper_bit) {
+ if (tamper_bit & TAMP_CR1_ITAMP5E) {
+ tamper_test_rtc_overflow();
+ } else if (tamper_bit & TAMP_CR1_ITAMP8E) {
+ tamper_test_counter_overflow();
+ }
+}
diff --git a/core/embed/trezorhal/tamper.h b/core/embed/trezorhal/tamper.h
new file mode 100644
index 0000000000..5d3fe12b09
--- /dev/null
+++ b/core/embed/trezorhal/tamper.h
@@ -0,0 +1,38 @@
+/*
+ * 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 .
+ */
+
+#ifndef TREZOR_HAL_TAMPER_H
+#define TREZOR_HAL_TAMPER_H
+
+#include
+
+// Tamper module enables the internal tamper detection on STM32 microcontroller
+// as well as external tamper input if it's available on the device
+
+// Initializes the tamper detection
+void tamper_init(void);
+
+// Triggers one of internal tampers.
+// The function is intended for experimentation with internal tamper mechanism
+// Use TAMP_CR1_xxx constants to as a parameter
+// Only TAMP_CR1_ITAMP5E (RTC) and TAMP_CR1_ITAMP8E (monotonic counter)
+// are supported
+void tamper_test(uint32_t tamper_type);
+
+#endif // TREZOR_HAL_TAMPER_H
diff --git a/core/site_scons/boards/stm32u5_common.py b/core/site_scons/boards/stm32u5_common.py
index 89bcf5575c..83f2a7dc1c 100644
--- a/core/site_scons/boards/stm32u5_common.py
+++ b/core/site_scons/boards/stm32u5_common.py
@@ -2,9 +2,7 @@ from __future__ import annotations
def stm32u5_common_files(env, defines, sources, paths):
- defines += [
- ("STM32_HAL_H", '""'),
- ]
+ defines += [("STM32_HAL_H", '""'), "USE_TAMPERS"]
paths += [
"embed/trezorhal/stm32u5",
@@ -34,6 +32,7 @@ def stm32u5_common_files(env, defines, sources, paths):
"vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_pwr_ex.c",
"vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_rcc.c",
"vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_rcc_ex.c",
+ "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_rtc.c",
"vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_sd.c",
"vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_spi.c",
"vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_sram.c",
@@ -53,6 +52,7 @@ def stm32u5_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32u5/systick.c",
"embed/trezorhal/stm32u5/random_delays.c",
"embed/trezorhal/stm32u5/rng.c",
+ "embed/trezorhal/stm32u5/tamper.c",
"embed/trezorhal/stm32u5/vectortable.s",
]