feat(core): add prepare build for STM32U

5, which sets option bytes so that boardloader starts correctly

[no changelog]
pull/3590/head
tychovrahe 3 months ago
parent e1161866da
commit 175bf3cd8a

@ -11,6 +11,7 @@ MAKE = make -j $(JOBS)
SCONS = scons -Q -j $(JOBS)
BUILD_DIR = build
PREPARE_BUILD_DIR = $(BUILD_DIR)/prepare
BOARDLOADER_BUILD_DIR = $(BUILD_DIR)/boardloader
BOOTLOADER_BUILD_DIR = $(BUILD_DIR)/bootloader
BOOTLOADER_CI_BUILD_DIR = $(BUILD_DIR)/bootloader_ci
@ -229,6 +230,10 @@ build: build_boardloader build_bootloader build_firmware build_prodtest build_un
build_embed: build_boardloader build_bootloader build_firmware # build boardloader, bootloader, firmware
build_prepare: ## build prepare
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
CMAKELISTS="$(CMAKELISTS)" $(PREPARE_BUILD_DIR)/prepare.bin
build_boardloader: ## build boardloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
CMAKELISTS="$(CMAKELISTS)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin
@ -283,9 +288,12 @@ build_cross: ## build mpy-cross port
## clean commands:
clean: clean_boardloader clean_bootloader clean_bootloader_emu clean_bootloader_ci clean_prodtest clean_reflash clean_firmware clean_unix clean_cross ## clean all
clean: clean_prepare clean_boardloader clean_bootloader clean_bootloader_emu clean_bootloader_ci clean_prodtest clean_reflash clean_firmware clean_unix clean_cross ## clean all
rm -f ".sconsign.dblite"
clean_prepare: ## clean prepare build
rm -rf $(PREPARE_BUILD_DIR)
clean_boardloader: ## clean boardloader build
rm -rf $(BOARDLOADER_BUILD_DIR)
@ -317,6 +325,9 @@ clean_cross: ## clean mpy-cross build
flash: flash_boardloader flash_bootloader flash_firmware ## flash everything using OpenOCD
flash_prepare: $(PREPARE_BUILD_DIR)/prepare.bin ## flash prepare using OpenOCD
$(OPENOCD) -c "init; reset halt; flash write_image erase $< $(FLASH_START); exit"
flash_boardloader: $(BOARDLOADER_BUILD_DIR)/boardloader.bin ## flash boardloader using OpenOCD
$(OPENOCD) -c "init; reset halt; flash write_image erase $< $(BOARDLOADER_START); exit"
@ -416,6 +427,8 @@ sizecheck: ## check sizes of binary files
test $(FIRMWARE_P2_MAXSIZE) -ge $(shell wc -c < $(FIRMWARE_BUILD_DIR)/firmware.bin.p2)
test $(FIRMWARE_MAXSIZE) -ge $(shell wc -c < $(FIRMWARE_BUILD_DIR)/firmware.bin)
ifeq ($(MCU),$(filter $(MCU),STM32F4))
combine: ## combine boardloader + bootloader + prodtest into one combined image
./tools/combine_firmware \
$(LAYOUT_FILE) \
@ -423,8 +436,6 @@ combine: ## combine boardloader + bootloader + prodtest into one combined image
-b BOARDLOADER $(BOARDLOADER_BUILD_DIR)/boardloader.bin \
-b BOOTLOADER $(BOOTLOADER_BUILD_DIR)/bootloader.bin \
-b FIRMWARE $(PRODTEST_BUILD_DIR)/prodtest.bin
ifeq ($(MCU),$(filter $(MCU),STM32F4))
combine_fw: ## combine boardloader + bootloader + firmware into one combined image
./tools/combine_firmware \
$(LAYOUT_FILE) \
@ -434,10 +445,19 @@ combine_fw: ## combine boardloader + bootloader + firmware into one combined ima
-b FIRMWARE $(FIRMWARE_BUILD_DIR)/firmware.bin.p1 \
-b FIRMWARE_P2 $(FIRMWARE_BUILD_DIR)/firmware.bin.p2
else ifeq ($(MCU),$(filter $(MCU),STM32U5))
combine: ## combine boardloader + bootloader + prodtest into one combined image
./tools/combine_firmware \
$(LAYOUT_FILE) \
$(PRODTEST_BUILD_DIR)/combined.bin \
-b FLASH $(PREPARE_BUILD_DIR)/prepare.bin \
-b BOARDLOADER $(BOARDLOADER_BUILD_DIR)/boardloader.bin \
-b BOOTLOADER $(BOOTLOADER_BUILD_DIR)/bootloader.bin \
-b FIRMWARE $(PRODTEST_BUILD_DIR)/prodtest.bin
combine_fw: ## combine boardloader + bootloader + firmware into one combined image
./tools/combine_firmware \
$(LAYOUT_FILE) \
$(PRODTEST_BUILD_DIR)/combined.bin \
-b FLASH $(PREPARE_BUILD_DIR)/prepare.bin \
-b BOARDLOADER $(BOARDLOADER_BUILD_DIR)/boardloader.bin \
-b BOOTLOADER $(BOOTLOADER_BUILD_DIR)/bootloader.bin \
-b FIRMWARE $(FIRMWARE_BUILD_DIR)/firmware.bin

@ -0,0 +1,144 @@
# pylint: disable=E0602
import os
import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
if TREZOR_MODEL not in ('T3T1', ):
# skip prepare build
env = Environment()
def build_prepare(target,source,env):
print(f'Prepare: nothing to build for Model {TREZOR_MODEL}')
program_bin = env.Command(
target='prepare.bin',
source=None,
action=build_prepare
)
Return()
FEATURES_WANTED = []
CCFLAGS_MOD = ''
CPPPATH_MOD = []
CPPDEFINES_MOD = ["PREPARE"]
SOURCE_MOD = []
CPPDEFINES_HAL = []
SOURCE_HAL = []
PATH_HAL = []
CPPPATH_MOD += [
'vendor/trezor-crypto',
'vendor/trezor-storage',
]
CCFLAGS_MOD += '-Wno-sequence-point '
env = Environment(ENV=os.environ,
CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')),
CONSTRAINTS=[],
CPPDEFINES_IMPLICIT=[]
)
FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL)
FILE_SUFFIX= env.get('ENV')['SUFFIX']
LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT']
SOURCE_PREPARE = [
f"embed/prepare/startup_{FILE_SUFFIX}.s",
'embed/prepare/main.c',
'embed/lib/terminal.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/mini_printf.c',
]
env.Replace(
CP='cp',
AS='arm-none-eabi-as',
AR='arm-none-eabi-ar',
CC='arm-none-eabi-gcc',
LINK='arm-none-eabi-gcc',
SIZE='arm-none-eabi-size',
STRIP='arm-none-eabi-strip',
OBJCOPY='arm-none-eabi-objcopy',
PYTHON='python',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py',)
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
env.Replace(
COPT=env.get('ENV').get('OPTIMIZE', '-Os'),
CCFLAGS='$COPT '
'-g3 '
'-nostdlib '
'-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common '
'-fsingle-precision-constant -fdata-sections -ffunction-sections '
'-ffreestanding '
'-fstack-protector-all '
+ env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD,
CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB',
LINKFLAGS=f"-T embed/prepare/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/prepare/prepare.map -Wl,--warn-common -Wl,--print-memory-usage",
CPPPATH=[
'embed/prepare',
'embed/lib',
'embed/models',
'embed/trezorhal',
'embed/extmod/modtrezorui',
'vendor/micropython/lib/cmsis/inc',
] + CPPPATH_MOD + PATH_HAL,
CPPDEFINES=[
'PREPARE',
'TREZOR_MODEL_'+TREZOR_MODEL,
'USE_HAL_DRIVER',
] + CPPDEFINES_MOD + CPPDEFINES_HAL,
ASFLAGS=env.get('ENV')['CPU_ASFLAGS'],
ASPPFLAGS='$CFLAGS $CCFLAGS',
)
env.Replace(
ALLSOURCES=SOURCE_MOD + SOURCE_PREPARE + SOURCE_HAL,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
#
# Program objects
#
obj_program = []
obj_program += env.Object(source=SOURCE_MOD)
obj_program += env.Object(source=SOURCE_PREPARE)
obj_program += env.Object(source=SOURCE_HAL)
program_elf = env.Command(
target='prepare.elf',
source=obj_program,
action=
'$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES -lc_nano -lgcc',
)
BINARY_NAME = f"build/prepare/prepare-{tools.get_model_identifier(TREZOR_MODEL)}"
BINARY_NAME += "-" + tools.get_version('embed/prepare/version.h')
BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
program_bin = env.Command(
target='prepare.bin',
source=program_elf,
action=[
'$OBJCOPY -O binary -j .vector_table -j .text -j .data -j .rodata -j .capabilities -j .sensitive $SOURCE $TARGET',
'$CP $TARGET ' + BINARY_NAME,
],
)

@ -9,5 +9,6 @@ SConscript('SConscript.bootloader_ci', variant_dir='build/bootloader_ci', duplic
SConscript('SConscript.bootloader_emu', variant_dir='build/bootloader_emu', duplicate=False)
SConscript('SConscript.firmware', variant_dir='build/firmware', duplicate=False)
SConscript('SConscript.prodtest', variant_dir='build/prodtest', duplicate=False)
SConscript('SConscript.prepare', variant_dir='build/prepare', duplicate=False)
SConscript('SConscript.reflash', variant_dir='build/reflash', duplicate=False)
SConscript('SConscript.unix', variant_dir='build/unix', duplicate=False)

@ -0,0 +1,34 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include TREZOR_BOARD
#include "lowlevel.h"
int main(void) {
// need the systick timer running before many HAL operations.
// want the PVD enabled before flash operations too.
periph_init();
if (sectrue != flash_configure_basic_option_bytes()) {
NVIC_SystemReset();
return 2;
}
return 0;
}

@ -0,0 +1,109 @@
/* Trezor v2 boardloader linker script */
ENTRY(reset_handler)
MEMORY {
FLASH (rx) : ORIGIN = 0x0C000000, LENGTH = 16K
SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100
BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100
SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K
SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K
SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */
SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */
SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K
}
main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */
_sstack = ORIGIN(SRAM2);
_estack = main_stack_base;
/* used by the startup code to populate variables used by the C code */
data_lma = LOADADDR(.data);
data_vma = ADDR(.data);
data_size = SIZEOF(.data);
/* used by the startup code to populate variables used by the C code */
sensitive_lma = LOADADDR(.sensitive);
sensitive_vma = ADDR(.sensitive);
sensitive_size = SIZEOF(.sensitive);
/* used by the startup code to wipe memory */
sram1_start = ORIGIN(SRAM1);
sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1);
sram2_start = ORIGIN(SRAM2);
sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2);
sram3_start = ORIGIN(SRAM3);
sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3);
sram4_start = ORIGIN(SRAM4);
sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4);
sram5_start = ORIGIN(SRAM5);
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
sram6_start = ORIGIN(SRAM6);
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
/* reserve 256 bytes for bootloader arguments */
boot_args_start = ORIGIN(BOOT_ARGS);
boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS);
SECTIONS {
.vector_table : ALIGN(512) {
KEEP(*(.vector_table));
} >FLASH AT>FLASH
.text : ALIGN(4) {
*(.text*);
. = ALIGN(4); /* make the section size a multiple of the word size */
} >FLASH AT>FLASH
.rodata : ALIGN(4) {
*(.rodata*);
. = ALIGN(4); /* make the section size a multiple of the word size */
} >FLASH AT>FLASH
.data : ALIGN(4) {
*(.data*);
. = ALIGN(8);
} >SRAM1 AT>FLASH
/DISCARD/ : {
*(.ARM.exidx*);
}
.bss : ALIGN(4) {
*(.bss*);
. = ALIGN(4);
} >SRAM1
.buf : ALIGN(4) {
*(.buf*);
. = ALIGN(4);
} >SRAM1
.stack : ALIGN(8) {
. = 16K; /* Overflow causes UsageFault */
} >SRAM2
.sensitive : ALIGN(8) {
*(.sensitive*);
. = ALIGN(4);
} >SRAM2 AT>FLASH
.fb : ALIGN(4) {
__fb_start = .;
*(.fb1*);
*(.fb2*);
__fb_end = .;
. = ALIGN(4);
} >SRAM3
.boot_args : ALIGN(8) {
*(.boot_command*);
. = ALIGN(8);
*(.boot_args*);
. = ALIGN(8);
} >BOOT_ARGS
/* Hard-coded address for capabilities structure */
.capabilities 0x0C00FF00 : {KEEP(*(.capabilities_section))}
}

@ -0,0 +1,107 @@
.syntax unified
.text
.global reset_handler
.type reset_handler, STT_FUNC
reset_handler:
// set the stack protection
ldr r0, =_sstack
add r0, r0, #16 // padding
msr MSPLIM, r0
bl SystemInit
// read the first rng data and save it
ldr r0, =0 // r0 - previous value
ldr r1, =0 // r1 - whether to compare the previous value
bl rng_read
// read the next rng data and make sure it is different than previous
// r0 - value returned from previous call
ldr r1, =1 // r1 - whether to compare the previous value
bl rng_read
mov r4, r0 // save TRNG output in r4
// wipe memory to remove any possible vestiges of sensitive data
fill_ram:
ldr r0, =sram1_start // r0 - point to beginning of SRAM
ldr r1, =sram1_end // r1 - point to byte after the end of SRAM
mov r2, r4 // r2 - the word-sized value to be written
bl memset_reg
ldr r0, =sram2_start // r0 - point to beginning of SRAM
ldr r1, =sram2_end // r1 - point to byte after the end of SRAM
mov r2, r4 // r2 - the word-sized value to be written
bl memset_reg
ldr r0, =sram3_start // r0 - point to beginning of SRAM
ldr r1, =sram3_end // r1 - point to byte after the end of SRAM
mov r2, r4 // r2 - the word-sized value to be written
bl memset_reg
ldr r0, =sram4_start // r0 - point to beginning of SRAM
ldr r1, =sram4_end // r1 - point to byte after the end of SRAM
mov r2, r4 // r2 - the word-sized value to be written
bl memset_reg
ldr r0, =sram5_start // r0 - point to beginning of SRAM
ldr r1, =sram5_end // r1 - point to byte after the end of SRAM
mov r2, r4 // r2 - the word-sized value to be written
bl memset_reg
ldr r0, =sram6_start // r0 - point to beginning of SRAM
ldr r1, =sram6_end // r1 - point to byte after the end of SRAM
mov r2, r4 // r2 - the word-sized value to be written
bl memset_reg
// setup environment for subsequent stage of code
clear_ram:
ldr r2, =0 // r2 - the word-sized value to be written
ldr r0, =sram1_start // r0 - point to beginning of SRAM
ldr r1, =sram1_end // r1 - point to byte after the end of SRAM
bl memset_reg
ldr r0, =sram2_start // r0 - point to beginning of SRAM
ldr r1, =sram2_end // r1 - point to byte after the end of SRAM
bl memset_reg
ldr r0, =sram3_start // r0 - point to beginning of SRAM
ldr r1, =sram3_end // r1 - point to byte after the end of SRAM
bl memset_reg
ldr r0, =sram4_start // r0 - point to beginning of SRAM
ldr r1, =sram4_end // r1 - point to byte after the end of SRAM
bl memset_reg
ldr r0, =sram5_start // r0 - point to beginning of SRAM
ldr r1, =sram5_end // r1 - point to byte after the end of SRAM
bl memset_reg
ldr r0, =sram6_start // r0 - point to beginning of SRAM
ldr r1, =sram6_end // r1 - point to byte after the end of SRAM
bl memset_reg
// copy data in from flash
ldr r0, =data_vma // dst addr
ldr r1, =data_lma // src addr
ldr r2, =data_size // size in bytes
bl memcpy
// copy sensitive data in from flash
ldr r0, =sensitive_vma // dst addr
ldr r1, =sensitive_lma // src addr
ldr r2, =sensitive_size // size in bytes
bl memcpy
// setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value
bl rng_get
ldr r1, = __stack_chk_guard
str r0, [r1]
// enter the application code
bl main
b shutdown_privileged
.end

@ -0,0 +1,4 @@
#define VERSION_MAJOR 0
#define VERSION_MINOR 0
#define VERSION_PATCH 1
#define VERSION_BUILD 0

@ -26,6 +26,7 @@ secbool flash_check_option_bytes(void);
void flash_lock_option_bytes(void);
void flash_unlock_option_bytes(void);
uint32_t flash_set_option_bytes(void);
secbool flash_configure_basic_option_bytes(void);
secbool flash_configure_option_bytes(void);
void periph_init(void);
secbool reset_flags_check(void);

@ -170,6 +170,18 @@ secbool flash_check_option_bytes(void) {
return sectrue;
}
secbool flash_check_basic_option_bytes(void) {
flash_wait_and_clear_status_flags();
if ((FLASH->OPTR & FLASH_OPTR_TZEN) == 0) {
return secfalse;
}
if (FLASH->SECBOOTADD0R != FALSH_SECBOOTADD0R_VALUE) {
return secfalse;
}
return sectrue;
}
void flash_lock_option_bytes(void) {
FLASH->NSCR |= FLASH_NSCR_OPTLOCK; // lock the option bytes
}
@ -186,6 +198,37 @@ void flash_unlock_option_bytes(void) {
; // wait until the flash option control register is unlocked
}
uint32_t flash_set_basic_option_bytes(void) {
if (flash_unlock_write() != sectrue) {
return 0;
}
flash_wait_and_clear_status_flags();
flash_unlock_option_bytes();
flash_wait_and_clear_status_flags();
FLASH->OPTR |= FLASH_OPTR_TZEN;
FLASH->SECBOOTADD0R = FALSH_SECBOOTADD0R_VALUE;
FLASH_WaitForLastOperation(HAL_MAX_DELAY);
FLASH->NSCR |= FLASH_NSCR_OPTSTRT;
uint32_t result =
flash_wait_and_clear_status_flags(); // wait until changes are committed
FLASH_WaitForLastOperation(HAL_MAX_DELAY);
FLASH->NSCR |= FLASH_NSCR_OBL_LAUNCH; // begin committing changes to flash
result =
flash_wait_and_clear_status_flags(); // wait until changes are committed
flash_lock_option_bytes();
if (flash_lock_write() != sectrue) {
return 0;
}
return result;
}
uint32_t flash_set_option_bytes(void) {
if (flash_unlock_write() != sectrue) {
return 0;
@ -239,6 +282,18 @@ void check_oem_keys(void) {
ensure(((FLASH->NSSR & FLASH_NSSR_OEM2LOCK) == 0) * sectrue, "OEM2 KEY SET");
}
secbool flash_configure_basic_option_bytes(void) {
if (sectrue == flash_check_basic_option_bytes()) {
return sectrue; // we DID NOT have to change the option bytes
}
do {
flash_set_basic_option_bytes();
} while (sectrue != flash_check_basic_option_bytes());
return secfalse; // notify that we DID have to change the option bytes
}
secbool flash_configure_option_bytes(void) {
if (sectrue == flash_check_option_bytes()) {
return sectrue; // we DID NOT have to change the option bytes

Loading…
Cancel
Save