Skip to content

Commit

Permalink
Fix boardloader build to avoid FW+bootloader assembler hacks
Browse files Browse the repository at this point in the history
  • Loading branch information
hiviah committed Aug 14, 2023
1 parent 3a9dfcf commit 2471338
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 3 deletions.
4 changes: 2 additions & 2 deletions core/SConscript.boardloader
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ FEATURES_WANTED = ["sd_card"]

CCFLAGS_MOD = ''
CPPPATH_MOD = []
CPPDEFINES_MOD = []
CPPDEFINES_MOD = ["BOARDLOADER"]
SOURCE_MOD = []
CPPDEFINES_HAL = []
SOURCE_HAL = []
Expand Down Expand Up @@ -71,7 +71,7 @@ SOURCE_BOARDLOADER = [
'embed/boardloader/main.c',
]

env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')))
env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), CONSTRAINTS=["boardloader_build"])

FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL)

Expand Down
159 changes: 159 additions & 0 deletions core/embed/boardloader/util.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
.syntax unified

.text

.global memset_reg
.type memset_reg, STT_FUNC
memset_reg:
// call with the following (note that the arguments are not validated prior to use):
// r0 - address of first word to write (inclusive)
// r1 - address of first word following the address in r0 to NOT write (exclusive)
// r2 - word value to be written
// both addresses in r0 and r1 needs to be divisible by 4!
.L_loop_begin:
str r2, [r0], 4 // store the word in r2 to the address in r0, post-indexed
cmp r0, r1
bne .L_loop_begin
bx lr

.global jump_to
.type jump_to, STT_FUNC
jump_to:
mov r4, r0 // save input argument r0 (the address of the next stage's vector table) (r4 is callee save)
// this subroutine re-points the exception handlers before the C code
// that comprises them has been given a good environment to run.
// therefore, this code needs to disable interrupts before the VTOR
// update. then, the reset_handler of the next stage needs to re-enable interrupts.
// the following prevents activation of all exceptions except Non-Maskable Interrupt (NMI).
// according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.8:
// "there is no requirement to insert memory barrier instructions after CPSID".
cpsid f
// wipe memory at the end of the current stage of code
bl clear_otg_hs_memory
ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM
ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM
ldr r2, =0 // r2 - the word-sized value to be written
bl memset_reg
ldr r0, =sram_start // r0 - point to beginning of SRAM
ldr r1, =sram_end // r1 - point to byte after the end of SRAM
ldr r2, =0 // r2 - the word-sized value to be written
bl memset_reg
mov lr, r4
// clear out the general purpose registers before the next stage's code can run (even the NMI exception handler)
ldr r0, =0
mov r1, r0
mov r2, r0
mov r3, r0
mov r4, r0
mov r5, r0
mov r6, r0
mov r7, r0
mov r8, r0
mov r9, r0
mov r10, r0
mov r11, r0
mov r12, r0
// give the next stage a fresh main stack pointer
ldr r0, [lr] // set r0 to the main stack pointer in the next stage's vector table
msr msp, r0 // give the next stage its main stack pointer
// point to the next stage's exception handlers
// AN321, section 4.11: "a memory barrier is not required after a VTOR update"
.set SCB_VTOR, 0xE000ED08 // reference "Cortex-M4 Devices Generic User Guide" section 4.3
ldr r0, =SCB_VTOR
str lr, [r0]
mov r0, r1 // zero out r0
// go on to the next stage
ldr lr, [lr, 4] // set lr to the next stage's reset_handler
bx lr

.global jump_to_unprivileged
.type jump_to_unprivileged, STT_FUNC
jump_to_unprivileged:
mov r4, r0 // save input argument r0 (the address of the next stage's vector table) (r4 is callee save)
// this subroutine re-points the exception handlers before the C code
// that comprises them has been given a good environment to run.
// therefore, this code needs to disable interrupts before the VTOR
// update. then, the reset_handler of the next stage needs to re-enable interrupts.
// the following prevents activation of all exceptions except Non-Maskable Interrupt (NMI).
// according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.8:
// "there is no requirement to insert memory barrier instructions after CPSID".
cpsid f
// wipe memory at the end of the current stage of code
bl clear_otg_hs_memory
ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM
ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM
ldr r2, =0 // r2 - the word-sized value to be written
bl memset_reg
ldr r0, =sram_start // r0 - point to beginning of SRAM
ldr r1, =sram_end // r1 - point to byte after the end of SRAM
ldr r2, =0 // r2 - the word-sized value to be written
bl memset_reg
mov lr, r4
// clear out the general purpose registers before the next stage's code can run (even the NMI exception handler)
ldr r0, =0
mov r1, r0
mov r2, r0
mov r3, r0
mov r4, r0
mov r5, r0
mov r6, r0
mov r7, r0
mov r8, r0
mov r9, r0
mov r10, r0
mov r11, r0
mov r12, r0
// give the next stage a fresh main stack pointer
ldr r0, [lr] // set r0 to the main stack pointer in the next stage's vector table
msr msp, r0 // give the next stage its main stack pointer
// point to the next stage's exception handlers
// AN321, section 4.11: "a memory barrier is not required after a VTOR update"
.set SCB_VTOR, 0xE000ED08 // reference "Cortex-M4 Devices Generic User Guide" section 4.3
ldr r0, =SCB_VTOR
str lr, [r0]
mov r0, r1 // zero out r0
// go on to the next stage
ldr lr, [lr, 4] // set lr to the next stage's reset_handler
// switch to unprivileged mode
ldr r0, =1
msr control, r0
isb
// jump
bx lr

.global shutdown_privileged
.type shutdown_privileged, STT_FUNC
// The function must be called from the privileged mode
shutdown_privileged:
cpsid f // disable all exceptions (except for NMI), the instruction is ignored in unprivileged mode
// if the exceptions weren't disabled, an exception handler (for example systick handler)
// could be called after the memory is erased, which would lead to another exception
ldr r0, =0
mov r1, r0
mov r2, r0
mov r3, r0
mov r4, r0
mov r5, r0
mov r6, r0
mov r7, r0
mov r8, r0
mov r9, r0
mov r10, r0
mov r11, r0
mov r12, r0
ldr lr, =0xffffffff
ldr r0, =ccmram_start
ldr r1, =ccmram_end
// set to value in r2
bl memset_reg
ldr r0, =sram_start
ldr r1, =sram_end
// set to value in r2
bl memset_reg
bl clear_otg_hs_memory
ldr r0, =1
msr control, r0 // jump to unprivileged mode
ldr r0, =0
b . // loop forever

.end
13 changes: 12 additions & 1 deletion core/site_scons/boards/stm32f4_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,21 @@ def stm32f4_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32f4/systick.c",
"embed/trezorhal/stm32f4/random_delays.c",
"embed/trezorhal/stm32f4/rng.c",
"embed/trezorhal/stm32f4/util.s",
"embed/trezorhal/stm32f4/vectortable.s",
]

# boardloader needs separate assembler for some function unencumbered by various FW+bootloader hacks
# this helps to prevent making a bug in boardloader which may be hard to fix since it's locked with write-protect
env_constraints = env.get("CONSTRAINTS")
if env_constraints and "boardloader_build" in env_constraints:
sources += [
"embed/boardloader/util.s",
]
else:
sources += [
"embed/trezorhal/stm32f4/util.s",
]

env.get("ENV")["RUST_INCLUDES"] = (
"-I../trezorhal/stm32f4;"
"-I../../vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc;"
Expand Down

0 comments on commit 2471338

Please sign in to comment.