You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/embed/trezorhal/stm32u5/tamper.c

218 lines
7.1 KiB

/*
* 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/>.
*/
#include <irq.h>
#include <supervise.h>
#include <tamper.h>
#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
// more flash efficient function than standard HAL
HAL_StatusTypeDef lsi_init(void) {
uint32_t tickstart = 0U;
FlagStatus pwrclkchanged = RESET;
/* Update LSI configuration in Backup Domain control register */
/* Requires to enable write access to Backup Domain of necessary */
if (__HAL_RCC_PWR_IS_CLK_DISABLED()) {
__HAL_RCC_PWR_CLK_ENABLE();
pwrclkchanged = SET;
}
if (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) {
/* Enable write access to Backup domain */
SET_BIT(PWR->DBPR, PWR_DBPR_DBP);
/* Wait for Backup domain Write protection disable */
tickstart = HAL_GetTick();
while (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) {
if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) {
/* Restore clock configuration if changed */
if (pwrclkchanged == SET) {
__HAL_RCC_PWR_CLK_DISABLE();
}
return HAL_TIMEOUT;
}
}
}
uint32_t bdcr_temp = RCC->BDCR;
if (RCC_LSI_DIV1 != (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
*/
/* The LSIPREDIV cannot be changed if the LSI is used by the IWDG or by
* the RTC */
/* Restore clock configuration if changed */
if (pwrclkchanged == SET) {
__HAL_RCC_PWR_CLK_DISABLE();
}
return HAL_ERROR;
}
/* Turn off LSI before changing RCC_BDCR_LSIPREDIV */
if ((bdcr_temp & RCC_BDCR_LSION) == RCC_BDCR_LSION) {
__HAL_RCC_LSI_DISABLE();
tickstart = HAL_GetTick();
/* Wait till LSI is disabled */
while (READ_BIT(RCC->BDCR, RCC_BDCR_LSIRDY) != 0U)
;
}
/* Set LSI division factor */
MODIFY_REG(RCC->BDCR, RCC_BDCR_LSIPREDIV, 0);
}
/* Enable the Internal Low Speed oscillator (LSI) */
__HAL_RCC_LSI_ENABLE();
/* Wait till LSI is ready */
while (READ_BIT(RCC->BDCR, RCC_BDCR_LSIRDY) == 0U)
;
/* Restore clock configuration if changed */
if (pwrclkchanged == SET) {
__HAL_RCC_PWR_CLK_DISABLE();
}
return HAL_OK;
}
void tamper_init(void) {
RCC_PeriphCLKInitTypeDef clk_init_def = {0};
// Enable LSI clock
lsi_init();
// 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();
PWR->BDCR1 |= PWR_BDCR1_MONEN;
// HAL_PWR_DisableBkUpAccess();
// Enable all internal tampers (4th and 10th are intentionally skipped)
// We select all of them despite some of them are never triggered
TAMP->CR1 =
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);
}
// Interrupt handle for all tamper events
// It displays an error message
void TAMP_IRQHandler(void) {
const char* reason = "UNKNOWN";
uint32_t sr = TAMP->SR;
TAMP->SCR = 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);
}