Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): fix handover to bootloader #4221

Merged
merged 1 commit into from
Sep 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions core/embed/trezorhal/stm32f4/bootutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,65 @@ static inline void __attribute__((always_inline)) delete_secrets(void) {
}
#endif // STM32U5

#ifdef STM32F4
// Ensure that we are running in privileged thread mode.
//
// This function is used only on STM32F4, where a direct jump to the
// bootloader is performed. It checks if we are in handler mode, and
// if so, it switches to privileged thread mode.
__attribute((naked, no_stack_protector)) static void ensure_thread_mode(void) {
__asm__ volatile(
// --------------------------------------------------------------
// Check if we are in handler mode
// --------------------------------------------------------------

"LDR R1, =0x1FF \n" // Get lower 9 bits of IPSR
"MRS R0, IPSR \n"
"ANDS R0, R0, R1 \n"
"CMP R0, #0 \n" // == 0 if in thread mode
"IT EQ \n"
"BXEQ LR \n" // return if in thread mode

// --------------------------------------------------------------
// Disable FP registers lazy stacking
// --------------------------------------------------------------

"LDR R1, = 0xE000EF34 \n" // FPU->FPCCR
"LDR R0, [R1] \n"
"BIC R0, R0, #1 \n" // Clear LSPACT to suppress lazy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from the description of LSPACT bit in programming manual:
Lazy state preservation active. Indicates whether lazy preservation of the floating-point state is active.
i would be expecting that this bit is managed by hardware and should be used by software as read only. Are you sure about this? For disabling of lazy stacking, i would expect LSPEN bit to be used, or by suppression do you mean that this should be only one time suppressed and this actually achieves it?

Copy link
Contributor Author

@cepetr cepetr Sep 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's kind of a one-time suppression.

If we hadn't done it here, the first FPU instruction used in the bootloader might cause lazy stacking and an unexpected overwrite of a portion of SRAM. There are some possible alternatives: 1) use any FPU instruction here instead of writing to FPU->FPPCR, which causes immediate stacking of FPU registers and clears the LSPACT bit, 2) possibly returning from handler mode with a different EXC_RETURN code...

I don't like it much either and I understand it looks a bit hacky.

// stacking
"STR R0, [R1] \n"

// --------------------------------------------------------------
// Exit handler mode, enter thread mode
// --------------------------------------------------------------

"MOV R0, SP \n" // Align stack pointer to 8 bytes
"AND R0, R0, #~7 \n"
"MOV SP, R0 \n"
"SUB SP, SP, #32 \n" // Allocate space for the stack frame

"MOV R0, #0 \n"
"STR R0, [SP, #0] \n" // future R0 = 0
"STR R0, [SP, #4] \n" // future R1 = 0
"STR R0, [SP, #8] \n" // future R2 = 0
"STR R0, [SP, #12] \n" // future R3 = 0
"STR R12, [SP, #16] \n" // future R12 = R12
"STR LR, [SP, #20] \n" // future LR = LR
"BIC LR, LR, #1 \n"
"STR LR, [SP, #24] \n" // return address = LR
"LDR R0, = 0x01000000 \n" // THUMB bit set
"STR R0, [SP, #28] \n" // future xPSR

"MRS R0, CONTROL \n" // Clear SPSEL to use MSP for thread
"BIC R0, R0, #3 \n" // Clear nPRIV to run in privileged mode
"MSR CONTROL, R0 \n"

"LDR LR, = 0xFFFFFFF9 \n" // Return to Secure Thread mode, use MSP
"BX LR \n");
}
#endif // STM32F4

// Reboots the device with the given boot command and arguments
static void __attribute__((noreturn))
reboot_with_args(boot_command_t command, const void* args, size_t args_size) {
Expand All @@ -98,6 +157,8 @@ reboot_with_args(boot_command_t command, const void* args, size_t args_size) {

mpu_reconfig(MPU_MODE_DISABLED);

ensure_thread_mode();

jump_to_with_flag(BOOTLOADER_START + IMAGE_HEADER_SIZE, g_boot_command);
for (;;)
;
Expand Down
Loading