diff --git a/core/embed/models/T3W1/boards/trezor_t3w1_revA.h b/core/embed/models/T3W1/boards/trezor_t3w1_revA.h index 507937fa6f2..24adf9d8c92 100644 --- a/core/embed/models/T3W1/boards/trezor_t3w1_revA.h +++ b/core/embed/models/T3W1/boards/trezor_t3w1_revA.h @@ -198,4 +198,6 @@ #define HW_REVISION_2_PORT GPIOI #define HW_REVISION_2_CLOCK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define TAMPER_INPUT_2 1 + #endif // TREZOR_T3W1_REVA_H_ diff --git a/core/embed/models/T3W1/boards/trezor_t3w1_revA0.h b/core/embed/models/T3W1/boards/trezor_t3w1_revA0.h index 315d2191a3f..6e24a3bc43e 100644 --- a/core/embed/models/T3W1/boards/trezor_t3w1_revA0.h +++ b/core/embed/models/T3W1/boards/trezor_t3w1_revA0.h @@ -171,4 +171,6 @@ #define HW_REVISION_2_PORT GPIOI #define HW_REVISION_2_CLOCK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define TAMPER_INPUT_2 1 + #endif // TREZOR_T3W1_REVA_H_ diff --git a/core/embed/models/T3W1/boards/trezor_t3w1_revB.h b/core/embed/models/T3W1/boards/trezor_t3w1_revB.h index a95ba44924b..b0d6b242624 100644 --- a/core/embed/models/T3W1/boards/trezor_t3w1_revB.h +++ b/core/embed/models/T3W1/boards/trezor_t3w1_revB.h @@ -198,4 +198,6 @@ #define HW_REVISION_2_PORT GPIOI #define HW_REVISION_2_CLOCK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define TAMPER_INPUT_2 1 + #endif // TREZOR_T3W1_REVA_H_ diff --git a/core/embed/projects/bootloader/main.c b/core/embed/projects/bootloader/main.c index e29fe9bc409..3f9c896e582 100644 --- a/core/embed/projects/bootloader/main.c +++ b/core/embed/projects/bootloader/main.c @@ -63,6 +63,9 @@ #ifdef USE_HASH_PROCESSOR #include #endif +#ifdef USE_TAMPER +#include +#endif #include #include "version.h" @@ -101,18 +104,26 @@ static void drivers_init(secbool *touch_initialized) { display_init(DISPLAY_RESET_CONTENT); unit_properties_init(); -#ifdef USE_TOUCH - secbool allow_touchless_mode = secfalse; -#if defined TREZOR_MODEL_T3T1 || defined TREZOR_MODEL_T3W1 - // on T3T1 and T3W1, tester needs to run without touch, so making an exception - // until unit variant is written in OTP +#if (defined TREZOR_MODEL_T3T1 || defined TREZOR_MODEL_T3W1) + // on T3T1 and T3W1, tester needs to run without touch and tamper, so making + // an exception until unit variant is written in OTP const secbool manufacturing_mode = unit_properties()->locked ? secfalse : sectrue; - allow_touchless_mode = manufacturing_mode; +#else + const secbool manufacturing_mode = secfalse; + (void)manufacturing_mode; // suppress unused variable warning +#endif +#ifdef USE_TAMPER + tamper_init(); + if (manufacturing_mode != sectrue) { + tamper_external_enable(); + } #endif + +#ifdef USE_TOUCH *touch_initialized = touch_init(); - if (allow_touchless_mode != sectrue) { + if (manufacturing_mode != sectrue) { ensure(*touch_initialized, "Touch screen panel was not loaded properly."); } #endif diff --git a/core/embed/projects/prodtest/main.c b/core/embed/projects/prodtest/main.c index 372f06ed21d..d40a3383d25 100644 --- a/core/embed/projects/prodtest/main.c +++ b/core/embed/projects/prodtest/main.c @@ -90,6 +90,10 @@ #include #endif +#ifdef USE_TAMPER +#include +#endif + #ifdef TREZOR_MODEL_T2T1 #define MODEL_IDENTIFIER "TREZOR2-" #else @@ -180,6 +184,9 @@ static void drivers_init(void) { display_init(DISPLAY_RESET_CONTENT); +#ifdef USE_TAMPER + tamper_init(); +#endif #ifdef USE_STORAGE_HWKEY secure_aes_init(); #endif diff --git a/core/embed/sys/startup/stm32u5/startup_init.c b/core/embed/sys/startup/stm32u5/startup_init.c index 727a15a1111..172c9a0faae 100644 --- a/core/embed/sys/startup/stm32u5/startup_init.c +++ b/core/embed/sys/startup/stm32u5/startup_init.c @@ -69,6 +69,62 @@ uint32_t SystemCoreClock = DEFAULT_FREQ * 1000000U; #pragma GCC optimize( \ "no-stack-protector") // applies to all functions in this file +/* + * This function replaces calls to universal, but flash-wasting + * function HAL_RCC_OscConfig. + * + * This is the configuration before the optimization: + * osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_LSI; + * osc_init_def.LSIState = RCC_LSI_ON; + * HAL_RCC_OscConfig(&osc_init_def); + */ +void lsi_init(void) { + /* Update LSI configuration in Backup Domain control register */ + /* Requires to enable write access to Backup Domain of necessary */ + + 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 */ + while (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) + ; + } + + 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 */ + + return; + } + + /* Turn off LSI before changing RCC_BDCR_LSIPREDIV */ + if ((bdcr_temp & RCC_BDCR_LSION) == RCC_BDCR_LSION) { + __HAL_RCC_LSI_DISABLE(); + + /* 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) + ; +} + void SystemInit(void) { // set flash wait states for an increasing HCLK frequency @@ -171,6 +227,12 @@ void SystemInit(void) { // enable power supply for GPIOG 2 to 15 PWR->SVMCR |= PWR_SVMCR_IO2SV; +#ifdef USE_LSE + // TODO +#else + lsi_init(); +#endif + __HAL_RCC_PWR_CLK_DISABLE(); // this will be overriden by static initialization diff --git a/core/embed/sys/tamper/inc/sys/tamper.h b/core/embed/sys/tamper/inc/sys/tamper.h index 17f52e4b48b..118aed2847d 100644 --- a/core/embed/sys/tamper/inc/sys/tamper.h +++ b/core/embed/sys/tamper/inc/sys/tamper.h @@ -17,8 +17,7 @@ * along with this program. If not, see . */ -#ifndef TREZOR_HAL_TAMPER_H -#define TREZOR_HAL_TAMPER_H +#pragma once #include @@ -30,13 +29,10 @@ // 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); +// Get status of external tamper inputs +uint8_t tamper_external_read(void); -#endif // KERNEL_MODE +// Enable external tamper inputs +void tamper_external_enable(void); -#endif // TREZOR_HAL_TAMPER_H +#endif // KERNEL_MODE diff --git a/core/embed/sys/tamper/stm32u5/tamper.c b/core/embed/sys/tamper/stm32u5/tamper.c index 880eecb6466..560edd8a03c 100644 --- a/core/embed/sys/tamper/stm32u5/tamper.c +++ b/core/embed/sys/tamper/stm32u5/tamper.c @@ -22,6 +22,7 @@ #include #include +#include #include #ifdef KERNEL_MODE @@ -37,84 +38,15 @@ * functions HAL_RCC_OscConfig and HAL_RCCEx_PeriphCLKConfig. * * This is the configuration before the optimization: - * osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_LSI; - * osc_init_def.LSIState = RCC_LSI_ON; - * HAL_RCC_OscConfig(&osc_init_def); - * * clk_init_def.PeriphClockSelection = RCC_PERIPHCLK_RTC; * clk_init_def.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; * HAL_RCCEx_PeriphCLKConfig(&clk_init_def); */ -HAL_StatusTypeDef lsi_init(void) { +HAL_StatusTypeDef clk_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) - ; - - /* Check for RTC Parameters used to output RTCCLK */ - assert_param(IS_RCC_RTCCLKSOURCE(pPeriphClkInit->RTCClockSelection)); /* Enable Power Clock */ if (__HAL_RCC_PWR_IS_CLK_DISABLED()) { __HAL_RCC_PWR_CLK_ENABLE(); @@ -133,7 +65,7 @@ HAL_StatusTypeDef lsi_init(void) { } /* Reset the Backup domain only if the RTC Clock source selection is modified * from default */ - bdcr_temp = READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL); + uint32_t bdcr_temp = READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL); if ((bdcr_temp != RCC_RTCCLKSOURCE_NO_CLK) && (bdcr_temp != RCC_RTCCLKSOURCE_LSI)) { @@ -160,7 +92,7 @@ HAL_StatusTypeDef lsi_init(void) { } /* Apply new RTC clock source selection */ - __HAL_RCC_RTC_CONFIG(RCC_PERIPHCLK_RTC); + __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSI); /* Restore clock configuration if changed */ if (pwrclkchanged == SET) { @@ -170,15 +102,15 @@ HAL_StatusTypeDef lsi_init(void) { } void tamper_init(void) { - // Enable LSI clock - lsi_init(); + // TODO LSE + clk_init(); // 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 + // They may be some as RTC/TAMP peripherals reside 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 | @@ -193,37 +125,37 @@ void tamper_init(void) { 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 + // // 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 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 peripherals 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 tampers to the "confirmed" mode + // => all secrets all deleted when any tamper event is triggered + TAMP->CR3 = 0; + +#ifdef TAMPER_INPUT_2 + // TAMP_IN2 level high + TAMP->CR2 |= TAMP_CR2_TAMP2TRG; +#endif + // 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 | @@ -235,11 +167,45 @@ void tamper_init(void) { NVIC_EnableIRQ(TAMP_IRQn); } +uint8_t tamper_external_read(void) { + uint8_t val = 0; + +#ifdef TAMPER_INPUT_2 + GPIO_InitTypeDef gpio = {0}; + gpio.Mode = GPIO_MODE_INPUT; + gpio.Pull = GPIO_PULLUP; + gpio.Pin = GPIO_PIN_0; + gpio.Speed = GPIO_SPEED_LOW; + HAL_GPIO_Init(GPIOA, &gpio); + + systick_delay_us(1); + + val |= GPIO_PIN_SET == HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) ? 2 : 0; + + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0); +#endif + + return val; +} + +void tamper_external_enable(void) { + // Enable external tampers +#ifdef TAMPER_INPUT_2 + TAMP->CR1 |= TAMP_CR1_TAMP2E; +#endif +} + // Interrupt handle for all tamper events // It displays an error message void TAMP_IRQHandler(void) { mpu_reconfig(MPU_MODE_DEFAULT); + // Disable external tamper, as its level detected + // and it would trigger again. We don't need it until reset. +#ifdef TAMPER_INPUT_2 + TAMP->CR1 &= ~TAMP_CR1_TAMP2E; +#endif + uint32_t sr = TAMP->SR; TAMP->SCR = sr;