Skip to content

Commit

Permalink
feat(core): reset peripherals during handovers
Browse files Browse the repository at this point in the history
[no changelog]
  • Loading branch information
cepetr committed Jan 30, 2025
1 parent 236c377 commit f990309
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 102 deletions.
4 changes: 4 additions & 0 deletions core/embed/sys/bsp/stm32f4/stm32f4xx_hal_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions core/embed/sys/startup/inc/sys/sysutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions core/embed/sys/startup/stm32/bootutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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();

Expand Down
95 changes: 95 additions & 0 deletions core/embed/sys/startup/stm32/sysutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
103 changes: 1 addition & 102 deletions core/embed/sys/task/stm32/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit f990309

Please sign in to comment.