From f99030938e6a668dd1cb4256a810e91af6cbe74d Mon Sep 17 00:00:00 2001 From: cepetr Date: Wed, 29 Jan 2025 21:36:01 +0100 Subject: [PATCH] feat(core): reset peripherals during handovers [no changelog] --- .../sys/bsp/stm32f4/stm32f4xx_hal_conf.h | 4 + core/embed/sys/startup/inc/sys/sysutils.h | 9 ++ core/embed/sys/startup/stm32/bootutils.c | 8 ++ core/embed/sys/startup/stm32/sysutils.c | 95 ++++++++++++++++ core/embed/sys/task/stm32/system.c | 103 +----------------- 5 files changed, 117 insertions(+), 102 deletions(-) diff --git a/core/embed/sys/bsp/stm32f4/stm32f4xx_hal_conf.h b/core/embed/sys/bsp/stm32f4/stm32f4xx_hal_conf.h index 467d575be6..ebd2e3ea69 100644 --- a/core/embed/sys/bsp/stm32f4/stm32f4xx_hal_conf.h +++ b/core/embed/sys/bsp/stm32f4/stm32f4xx_hal_conf.h @@ -413,6 +413,10 @@ #endif /* USE_FULL_ASSERT */ +#ifndef HardFault_IRQn +#define HardFault_IRQn (-13) // not defined in stm32lib/cmsis/stm32f429xx.h +#endif + #ifdef __cplusplus } #endif diff --git a/core/embed/sys/startup/inc/sys/sysutils.h b/core/embed/sys/startup/inc/sys/sysutils.h index c3bba5f6bd..7508610226 100644 --- a/core/embed/sys/startup/inc/sys/sysutils.h +++ b/core/embed/sys/startup/inc/sys/sysutils.h @@ -49,8 +49,17 @@ void ensure_thread_mode(void); void ensure_compatible_settings(void); // Clears USB peripheral fifo memory +// +// Used to wipe sensitive data from USB peripheral memory. void clear_otg_hs_memory(void); +// Resets critical peripherals, disables all interrupts, and clears +// pending interrupts in the NVIC controller. +// +// This function is used to stop pending DMA transfers and interrupts, +// ensuring it is safe to jump to the next stage or initiate rescue mode. +void reset_peripherals_and_interrupts(void); + // Jumps to the binary using its vector table. // // The target binary is called with interrupts disabled, and all registers diff --git a/core/embed/sys/startup/stm32/bootutils.c b/core/embed/sys/startup/stm32/bootutils.c index 5d79ff7fce..1522ac658a 100644 --- a/core/embed/sys/startup/stm32/bootutils.c +++ b/core/embed/sys/startup/stm32/bootutils.c @@ -104,6 +104,10 @@ static void reboot_with_args_phase_2(uint32_t arg1, uint32_t arg2) { // any variables in the .bss and .data sections, so we must // be careful and avoid using them altogether. + // Reset peripherals (so we are sure that no DMA is pending) + // and disable all interrupts and clear all pending ones + reset_peripherals_and_interrupts(); + // Clear unused part of stack clear_unused_stack(); @@ -174,6 +178,10 @@ static void jump_to_next_stage_phase_2(uint32_t arg1, uint32_t arg2) { // any variables in the .bss and .data sections, so we must // be careful and avoid using them altogether. + // Reset peripherals (so we are sure that no DMA is pending) + // and disable all interrupts and clear all pending ones + reset_peripherals_and_interrupts(); + // Clear unused part of stack clear_unused_stack(); diff --git a/core/embed/sys/startup/stm32/sysutils.c b/core/embed/sys/startup/stm32/sysutils.c index 2e493ceddb..8ef51dbc95 100644 --- a/core/embed/sys/startup/stm32/sysutils.c +++ b/core/embed/sys/startup/stm32/sysutils.c @@ -260,4 +260,99 @@ __attribute((naked, noreturn, no_stack_protector)) void jump_to_vectbl( ); } +void reset_peripherals_and_interrupts(void) { +#ifdef __HAL_RCC_DMA2D_FORCE_RESET + __HAL_RCC_DMA2D_CLK_DISABLE(); + __HAL_RCC_DMA2D_FORCE_RESET(); + __HAL_RCC_DMA2D_RELEASE_RESET(); +#endif + +#ifdef __HAL_RCC_DSI_FORCE_RESET + __HAL_RCC_DSI_CLK_DISABLE(); + __HAL_RCC_DSI_FORCE_RESET(); + __HAL_RCC_DSI_RELEASE_RESET(); +#endif + +#ifdef __HAL_RCC_GFXMMU_FORCE_RESET + __HAL_RCC_GFXMMU_CLK_DISABLE(); + __HAL_RCC_GFXMMU_FORCE_RESET(); + __HAL_RCC_GFXMMU_RELEASE_RESET(); +#endif + +#ifdef __HAL_RCC_LTDC_FORCE_RESET + __HAL_RCC_LTDC_CLK_DISABLE(); + __HAL_RCC_LTDC_FORCE_RESET(); + __HAL_RCC_LTDC_RELEASE_RESET(); +#endif + +#ifdef __HAL_RCC_GPDMA1_FORCE_RESET + __HAL_RCC_GPDMA1_CLK_DISABLE(); + __HAL_RCC_GPDMA1_FORCE_RESET(); + __HAL_RCC_GPDMA1_RELEASE_RESET(); +#endif + +#ifdef __HAL_RCC_DMA1_FORCE_RESET + __HAL_RCC_DMA1_CLK_DISABLE(); + __HAL_RCC_DMA1_FORCE_RESET(); + __HAL_RCC_DMA1_RELEASE_RESET(); +#endif + +#ifdef __HAL_RCC_DMA2_FORCE_RESET + __HAL_RCC_DMA2_CLK_DISABLE(); + __HAL_RCC_DMA2_FORCE_RESET(); + __HAL_RCC_DMA2_RELEASE_RESET(); +#endif + + // Disable all NVIC interrupts and clear pending flags + // so later the global interrupt can be re-enabled without + // firing any pending interrupt + for (int irqn = 0; irqn < 255; irqn++) { + NVIC_DisableIRQ(irqn); + NVIC_ClearPendingIRQ(irqn); + } + + // Disable SysTick + SysTick->CTRL = 0; + + // Clear PENDSV flag to prevent the PendSV_Handler call + SCB->ICSR &= ~SCB_ICSR_PENDSVSET_Msk; + + // Clear SCB->SHCSR exception flags so we can return back + // to thread mode without any exception active + + uint32_t preserved_flag = 0; + + switch ((__get_IPSR() & IPSR_ISR_Msk) - 16) { + case MemoryManagement_IRQn: + preserved_flag = SCB_SHCSR_MEMFAULTACT_Msk; + break; + case BusFault_IRQn: + preserved_flag = SCB_SHCSR_BUSFAULTACT_Msk; + break; + case UsageFault_IRQn: + preserved_flag = SCB_SHCSR_USGFAULTACT_Msk; + break; + case PendSV_IRQn: + preserved_flag = SCB_SHCSR_PENDSVACT_Msk; + break; + case SysTick_IRQn: + preserved_flag = SCB_SHCSR_SYSTICKACT_Msk; + break; + case SVCall_IRQn: + preserved_flag = SCB_SHCSR_SVCALLACT_Msk; + break; + case HardFault_IRQn: + default: + break; + } + + const uint32_t cleared_flags = + SCB_SHCSR_MEMFAULTACT_Msk | SCB_SHCSR_BUSFAULTACT_Msk | + SCB_SHCSR_USGFAULTACT_Msk | SCB_SHCSR_SVCALLACT_Msk | + SCB_SHCSR_MONITORACT_Msk | SCB_SHCSR_PENDSVACT_Msk | + SCB_SHCSR_SYSTICKACT_Msk; + + SCB->SHCSR &= ~(cleared_flags & ~preserved_flag); +} + #endif // KERNEL_MODE diff --git a/core/embed/sys/task/stm32/system.c b/core/embed/sys/task/stm32/system.c index 782c04decf..6af3531231 100644 --- a/core/embed/sys/task/stm32/system.c +++ b/core/embed/sys/task/stm32/system.c @@ -38,10 +38,6 @@ #include "../stm32f4/startup_init.h" #endif -#ifndef HardFault_IRQn -#define HardFault_IRQn (-13) // not defined in stm32lib/cmsis/stm32429xx.h -#endif - #ifdef KERNEL_MODE void system_init(systask_error_handler_t error_handler) { @@ -81,109 +77,12 @@ void system_exit_fatal_ex(const char* message, size_t message_len, systask_exit_fatal(NULL, message, message_len, file, file_len, line); } -__attribute__((used)) static void emergency_reset(void) { - // Reset peripherals - -#ifdef __HAL_RCC_DMA2D_FORCE_RESET - __HAL_RCC_DMA2D_CLK_DISABLE(); - __HAL_RCC_DMA2D_FORCE_RESET(); - __HAL_RCC_DMA2D_RELEASE_RESET(); -#endif - -#ifdef __HAL_RCC_DSI_FORCE_RESET - __HAL_RCC_DSI_CLK_DISABLE(); - __HAL_RCC_DSI_FORCE_RESET(); - __HAL_RCC_DSI_RELEASE_RESET(); -#endif - -#ifdef __HAL_RCC_GFXMMU_FORCE_RESET - __HAL_RCC_GFXMMU_CLK_DISABLE(); - __HAL_RCC_GFXMMU_FORCE_RESET(); - __HAL_RCC_GFXMMU_RELEASE_RESET(); -#endif - -#ifdef __HAL_RCC_LTDC_FORCE_RESET - __HAL_RCC_LTDC_CLK_DISABLE(); - __HAL_RCC_LTDC_FORCE_RESET(); - __HAL_RCC_LTDC_RELEASE_RESET(); -#endif - -#ifdef __HAL_RCC_GPDMA1_FORCE_RESET - __HAL_RCC_GPDMA1_CLK_DISABLE(); - __HAL_RCC_GPDMA1_FORCE_RESET(); - __HAL_RCC_GPDMA1_RELEASE_RESET(); -#endif - -#ifdef __HAL_RCC_DMA1_FORCE_RESET - __HAL_RCC_DMA1_CLK_DISABLE(); - __HAL_RCC_DMA1_FORCE_RESET(); - __HAL_RCC_DMA1_RELEASE_RESET(); -#endif - -#ifdef __HAL_RCC_DMA2_FORCE_RESET - __HAL_RCC_DMA2_CLK_DISABLE(); - __HAL_RCC_DMA2_FORCE_RESET(); - __HAL_RCC_DMA2_RELEASE_RESET(); -#endif - - // Disable all NVIC interrupts and clear pending flags - // so later the global interrupt can be re-enabled without - // firing any pending interrupt - for (int irqn = 0; irqn < 255; irqn++) { - NVIC_DisableIRQ(irqn); - NVIC_ClearPendingIRQ(irqn); - } - - // Disable SysTick - SysTick->CTRL = 0; - - // Clear PENDSV flag to prevent the PendSV_Handler call - SCB->ICSR &= ~SCB_ICSR_PENDSVSET_Msk; - - // Clear SCB->SHCSR exception flags so we can return back - // to thread mode without any exception active - - uint32_t preserved_flag = 0; - - switch ((__get_IPSR() & IPSR_ISR_Msk) - 16) { - case MemoryManagement_IRQn: - preserved_flag = SCB_SHCSR_MEMFAULTACT_Msk; - break; - case BusFault_IRQn: - preserved_flag = SCB_SHCSR_BUSFAULTACT_Msk; - break; - case UsageFault_IRQn: - preserved_flag = SCB_SHCSR_USGFAULTACT_Msk; - break; - case PendSV_IRQn: - preserved_flag = SCB_SHCSR_PENDSVACT_Msk; - break; - case SysTick_IRQn: - preserved_flag = SCB_SHCSR_SYSTICKACT_Msk; - break; - case SVCall_IRQn: - preserved_flag = SCB_SHCSR_SVCALLACT_Msk; - break; - case HardFault_IRQn: - default: - break; - } - - const uint32_t cleared_flags = - SCB_SHCSR_MEMFAULTACT_Msk | SCB_SHCSR_BUSFAULTACT_Msk | - SCB_SHCSR_USGFAULTACT_Msk | SCB_SHCSR_SVCALLACT_Msk | - SCB_SHCSR_MONITORACT_Msk | SCB_SHCSR_PENDSVACT_Msk | - SCB_SHCSR_SYSTICKACT_Msk; - - SCB->SHCSR &= ~(cleared_flags & ~preserved_flag); -} - __attribute((noreturn, no_stack_protector)) static void system_emergency_rescue_phase_2(uint32_t arg1, uint32_t arg2) { systask_error_handler_t error_handler = (systask_error_handler_t)arg1; // Reset peripherals (so we are sure that no DMA is pending) - emergency_reset(); + reset_peripherals_and_interrupts(); // Copy pminfo from to our stack // MPU is now disable, we have full access to bootargs.