From 8150636a81dc2010d910a8c20418073c9ad5c8e1 Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Wed, 28 Jun 2023 10:51:30 +0200 Subject: [PATCH] feat(core): add basic support for STM32U5 --- core/.changelog.d/3370.added | 1 + core/Makefile | 32 +- core/SConscript.boardloader | 20 +- core/SConscript.bootloader | 27 +- core/SConscript.bootloader_ci | 27 +- core/SConscript.bootloader_emu | 8 +- core/SConscript.firmware | 55 +- core/SConscript.prodtest | 33 +- core/SConscript.reflash | 20 +- core/SConscript.unix | 6 +- .../embed/boardloader/.changelog.d/3370.added | 1 + core/embed/boardloader/main.c | 71 +++ .../{memory.ld => memory_stm32f4.ld} | 0 core/embed/boardloader/memory_stm32u5a.ld | 109 ++++ .../{startup.s => startup_stm32f4.s} | 0 core/embed/boardloader/startup_stm32u5.s | 102 ++++ core/embed/bootloader/.changelog.d/3370.added | 1 + core/embed/bootloader/emulator.c | 7 +- core/embed/bootloader/main.c | 84 ++- .../{memory.ld => memory_stm32f4.ld} | 2 + core/embed/bootloader/memory_stm32u5a.ld | 107 ++++ core/embed/bootloader/messages.c | 7 +- .../{startup.s => startup_stm32f4.s} | 0 core/embed/bootloader/startup_stm32u5.s | 78 +++ .../bootloader_ci/.changelog.d/3370.added | 1 + .../{memory.ld => memory_stm32f4.ld} | 20 +- core/embed/bootloader_ci/memory_stm32u5a.ld | 107 ++++ .../{startup.s => startup_stm32f4.s} | 0 core/embed/bootloader_ci/startup_stm32u5.s | 78 +++ core/embed/firmware/main.c | 34 +- core/embed/firmware/memory_T.ld | 1 + .../firmware/{startup.S => startup_stm32f4.S} | 12 - core/embed/firmware/startup_stm32u5.S | 67 ++ .../stm32f4 => lib}/compiler_traits.h | 0 core/embed/models/layout_common.h | 1 + core/embed/models/model_D001.h | 1 + core/embed/models/model_T2B1.h | 1 + core/embed/models/model_T2T1.h | 1 + core/embed/prodtest/.changelog.d/3370.added | 1 + core/embed/prodtest/main.c | 2 - .../prodtest/{memory.ld => memory_stm32f4.ld} | 1 + core/embed/prodtest/memory_stm32u5a.ld | 123 ++++ .../prodtest/{startup.s => startup_stm32f4.s} | 0 core/embed/prodtest/startup_stm32u5.s | 67 ++ .../reflash/{memory.ld => memory_stm32f4.ld} | 0 core/embed/reflash/memory_stm32u5a.ld | 123 ++++ .../reflash/{startup.s => startup_stm32f4.s} | 0 core/embed/reflash/startup_stm32u5.s | 67 ++ core/embed/rust/build.rs | 2 +- core/embed/trezorhal/board_capabilities.h | 1 - core/embed/trezorhal/lowlevel.h | 1 + core/embed/trezorhal/mpu.h | 1 + core/embed/trezorhal/secret.h | 24 + core/embed/trezorhal/secure_aes.h | 40 ++ .../trezorhal/stm32f4/board_capabilities.c | 1 + core/embed/trezorhal/stm32f4/fault_handlers.c | 18 + core/embed/trezorhal/stm32f4/irq.h | 3 + core/embed/trezorhal/stm32f4/mpu.c | 4 + core/embed/trezorhal/stm32f4/platform.h | 2 + core/embed/trezorhal/stm32f4/secret.c | 4 + core/embed/trezorhal/stm32f4/supervise.c | 17 +- core/embed/trezorhal/stm32f4/usb.c | 2 + core/embed/trezorhal/stm32f4/usbd_conf.c | 103 +++- core/embed/trezorhal/stm32f4/util.s | 12 + .../trezorhal/stm32u5/board_capabilities.c | 1 + core/embed/trezorhal/stm32u5/common.c | 205 +++++++ core/embed/trezorhal/stm32u5/dma2d.c | 1 + core/embed/trezorhal/stm32u5/fault_handlers.c | 22 + core/embed/trezorhal/stm32u5/flash.c | 567 +++++++++++++++++ core/embed/trezorhal/stm32u5/i2c.c | 441 ++++++++++++++ core/embed/trezorhal/stm32u5/i2c.h | 1 + core/embed/trezorhal/stm32u5/irq.h | 1 + core/embed/trezorhal/stm32u5/limited_util.s | 145 +++++ core/embed/trezorhal/stm32u5/lowlevel.c | 311 ++++++++++ core/embed/trezorhal/stm32u5/mpu.c | 258 ++++++++ core/embed/trezorhal/stm32u5/platform.c | 212 +++++++ core/embed/trezorhal/stm32u5/platform.h | 56 ++ core/embed/trezorhal/stm32u5/random_delays.c | 1 + core/embed/trezorhal/stm32u5/rng.c | 1 + core/embed/trezorhal/stm32u5/sbu.c | 1 + core/embed/trezorhal/stm32u5/secret.c | 162 +++++ core/embed/trezorhal/stm32u5/secure_aes.c | 117 ++++ .../trezorhal/stm32u5/stm32u5xx_hal_conf.h | 563 +++++++++++++++++ core/embed/trezorhal/stm32u5/supervise.c | 1 + core/embed/trezorhal/stm32u5/supervise.h | 1 + core/embed/trezorhal/stm32u5/systemview.h | 1 + core/embed/trezorhal/stm32u5/systick.c | 1 + core/embed/trezorhal/stm32u5/systick.h | 1 + core/embed/trezorhal/stm32u5/tamper.c | 217 +++++++ core/embed/trezorhal/stm32u5/trustzone.c | 200 ++++++ core/embed/trezorhal/stm32u5/usb.c | 1 + core/embed/trezorhal/stm32u5/usb_hid-impl.h | 1 + core/embed/trezorhal/stm32u5/usb_vcp-impl.h | 1 + .../embed/trezorhal/stm32u5/usb_webusb-impl.h | 1 + core/embed/trezorhal/stm32u5/usbd_conf.c | 1 + core/embed/trezorhal/stm32u5/usbd_conf.h | 1 + core/embed/trezorhal/stm32u5/usbd_core.c | 1 + core/embed/trezorhal/stm32u5/usbd_core.h | 1 + core/embed/trezorhal/stm32u5/usbd_ctlreq.c | 1 + core/embed/trezorhal/stm32u5/usbd_ctlreq.h | 1 + core/embed/trezorhal/stm32u5/usbd_def.h | 1 + core/embed/trezorhal/stm32u5/usbd_ioreq.c | 1 + core/embed/trezorhal/stm32u5/usbd_ioreq.h | 1 + core/embed/trezorhal/stm32u5/util.s | 205 +++++++ core/embed/trezorhal/stm32u5/vectortable.s | 177 ++++++ core/embed/trezorhal/tamper.h | 38 ++ core/embed/trezorhal/trustzone.h | 574 ++++++++++++++++++ core/embed/trezorhal/unix/platform.h | 2 + core/site_scons/boards/stm32f4_common.py | 6 + core/site_scons/boards/stm32u5_common.py | 91 +++ core/tools/combine_firmware | 60 +- legacy/Makefile | 2 +- storage/flash_common.h | 5 + storage/{flash_common.c => flash_common_f4.c} | 14 + storage/tests/c/Makefile | 2 +- 115 files changed, 6245 insertions(+), 173 deletions(-) create mode 100644 core/.changelog.d/3370.added create mode 100644 core/embed/boardloader/.changelog.d/3370.added rename core/embed/boardloader/{memory.ld => memory_stm32f4.ld} (100%) create mode 100644 core/embed/boardloader/memory_stm32u5a.ld rename core/embed/boardloader/{startup.s => startup_stm32f4.s} (100%) create mode 100644 core/embed/boardloader/startup_stm32u5.s create mode 100644 core/embed/bootloader/.changelog.d/3370.added rename core/embed/bootloader/{memory.ld => memory_stm32f4.ld} (96%) create mode 100644 core/embed/bootloader/memory_stm32u5a.ld rename core/embed/bootloader/{startup.s => startup_stm32f4.s} (100%) create mode 100644 core/embed/bootloader/startup_stm32u5.s create mode 100644 core/embed/bootloader_ci/.changelog.d/3370.added rename core/embed/bootloader_ci/{memory.ld => memory_stm32f4.ld} (78%) create mode 100644 core/embed/bootloader_ci/memory_stm32u5a.ld rename core/embed/bootloader_ci/{startup.s => startup_stm32f4.s} (100%) create mode 100644 core/embed/bootloader_ci/startup_stm32u5.s rename core/embed/firmware/{startup.S => startup_stm32f4.S} (90%) create mode 100644 core/embed/firmware/startup_stm32u5.S rename core/embed/{trezorhal/stm32f4 => lib}/compiler_traits.h (100%) create mode 100644 core/embed/prodtest/.changelog.d/3370.added rename core/embed/prodtest/{memory.ld => memory_stm32f4.ld} (98%) create mode 100644 core/embed/prodtest/memory_stm32u5a.ld rename core/embed/prodtest/{startup.s => startup_stm32f4.s} (100%) create mode 100644 core/embed/prodtest/startup_stm32u5.s rename core/embed/reflash/{memory.ld => memory_stm32f4.ld} (100%) create mode 100644 core/embed/reflash/memory_stm32u5a.ld rename core/embed/reflash/{startup.s => startup_stm32f4.s} (100%) create mode 100644 core/embed/reflash/startup_stm32u5.s create mode 100644 core/embed/trezorhal/secure_aes.h create mode 100644 core/embed/trezorhal/stm32f4/fault_handlers.c create mode 120000 core/embed/trezorhal/stm32u5/board_capabilities.c create mode 100644 core/embed/trezorhal/stm32u5/common.c create mode 120000 core/embed/trezorhal/stm32u5/dma2d.c create mode 100644 core/embed/trezorhal/stm32u5/fault_handlers.c create mode 100644 core/embed/trezorhal/stm32u5/flash.c create mode 100644 core/embed/trezorhal/stm32u5/i2c.c create mode 120000 core/embed/trezorhal/stm32u5/i2c.h create mode 120000 core/embed/trezorhal/stm32u5/irq.h create mode 100644 core/embed/trezorhal/stm32u5/limited_util.s create mode 100644 core/embed/trezorhal/stm32u5/lowlevel.c create mode 100644 core/embed/trezorhal/stm32u5/mpu.c create mode 100644 core/embed/trezorhal/stm32u5/platform.c create mode 100644 core/embed/trezorhal/stm32u5/platform.h create mode 120000 core/embed/trezorhal/stm32u5/random_delays.c create mode 120000 core/embed/trezorhal/stm32u5/rng.c create mode 120000 core/embed/trezorhal/stm32u5/sbu.c create mode 100644 core/embed/trezorhal/stm32u5/secret.c create mode 100644 core/embed/trezorhal/stm32u5/secure_aes.c create mode 100644 core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h create mode 120000 core/embed/trezorhal/stm32u5/supervise.c create mode 120000 core/embed/trezorhal/stm32u5/supervise.h create mode 120000 core/embed/trezorhal/stm32u5/systemview.h create mode 120000 core/embed/trezorhal/stm32u5/systick.c create mode 120000 core/embed/trezorhal/stm32u5/systick.h create mode 100644 core/embed/trezorhal/stm32u5/tamper.c create mode 100644 core/embed/trezorhal/stm32u5/trustzone.c create mode 120000 core/embed/trezorhal/stm32u5/usb.c create mode 120000 core/embed/trezorhal/stm32u5/usb_hid-impl.h create mode 120000 core/embed/trezorhal/stm32u5/usb_vcp-impl.h create mode 120000 core/embed/trezorhal/stm32u5/usb_webusb-impl.h create mode 120000 core/embed/trezorhal/stm32u5/usbd_conf.c create mode 120000 core/embed/trezorhal/stm32u5/usbd_conf.h create mode 120000 core/embed/trezorhal/stm32u5/usbd_core.c create mode 120000 core/embed/trezorhal/stm32u5/usbd_core.h create mode 120000 core/embed/trezorhal/stm32u5/usbd_ctlreq.c create mode 120000 core/embed/trezorhal/stm32u5/usbd_ctlreq.h create mode 120000 core/embed/trezorhal/stm32u5/usbd_def.h create mode 120000 core/embed/trezorhal/stm32u5/usbd_ioreq.c create mode 120000 core/embed/trezorhal/stm32u5/usbd_ioreq.h create mode 100644 core/embed/trezorhal/stm32u5/util.s create mode 100644 core/embed/trezorhal/stm32u5/vectortable.s create mode 100644 core/embed/trezorhal/tamper.h create mode 100644 core/embed/trezorhal/trustzone.h create mode 100644 core/site_scons/boards/stm32u5_common.py rename storage/{flash_common.c => flash_common_f4.c} (91%) diff --git a/core/.changelog.d/3370.added b/core/.changelog.d/3370.added new file mode 100644 index 0000000000..20f7c86466 --- /dev/null +++ b/core/.changelog.d/3370.added @@ -0,0 +1 @@ +Added basic support for STM32U5 diff --git a/core/Makefile b/core/Makefile index 168e2d0a22..6d450d40e6 100644 --- a/core/Makefile +++ b/core/Makefile @@ -41,21 +41,29 @@ TEST_LANG ?= "en" OPENOCD_INTERFACE ?= stlink # OpenOCD transport default. Alternative: jtag OPENOCD_TRANSPORT ?= hla_swd -OPENOCD = openocd -f interface/$(OPENOCD_INTERFACE).cfg -c "transport select $(OPENOCD_TRANSPORT)" -f target/stm32f4x.cfg -OPENOCD_T1 = openocd -f interface/$(OPENOCD_INTERFACE).cfg -c "transport select $(OPENOCD_TRANSPORT)" -f target/stm32f2x.cfg +ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),T R DISC1)) +OPENOCD_TARGET = target/stm32f4x.cfg BOARDLOADER_START = 0x08000000 +BOARDLOADER_END = 0x0800C000 BOOTLOADER_START = 0x08020000 -FIRMWARE_P1_START = 0x08040000 +FIRMWARE_START = 0x08040000 FIRMWARE_P2_START = 0x08120000 PRODTEST_START = 0x08040000 -FIRMWARE_T1_START = 0x08010000 - BOARDLOADER_MAXSIZE = 49152 BOOTLOADER_MAXSIZE = 131072 FIRMWARE_P1_MAXSIZE = 786432 FIRMWARE_P2_MAXSIZE = 917504 FIRMWARE_MAXSIZE = 1703936 +else ifeq ($(TREZOR_MODEL), 1) +OPENOCD_TARGET = target/stm32f2x.cfg +FIRMWARE_START = 0x08010000 +else +$(error Unknown TREZOR_MODEL: $(TREZOR_MODEL)) +endif + + +OPENOCD = openocd -f interface/$(OPENOCD_INTERFACE).cfg -c "transport select $(OPENOCD_TRANSPORT)" -f $(OPENOCD_TARGET) CFLAGS += -DSCM_REVISION='\"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')\"' @@ -289,10 +297,12 @@ flash_prodtest: $(PRODTEST_BUILD_DIR)/prodtest.bin ## flash prodtest using OpenO $(OPENOCD) -c "init; reset halt; flash write_image erase $< $(PRODTEST_START); exit" flash_firmware: $(FIRMWARE_BUILD_DIR)/firmware.bin ## flash firmware using OpenOCD - $(OPENOCD) -c "init; reset halt; flash write_image erase $<.p1 $(FIRMWARE_P1_START); flash write_image erase $<.p2 $(FIRMWARE_P2_START); exit" +ifdef FIRMWARE_P2_START + $(OPENOCD) -c "init; reset halt; flash write_image erase $<.p1 $(FIRMWARE_START); flash write_image erase $<.p2 $(FIRMWARE_P2_START); exit" -flash_firmware_t1: $(FIRMWARE_BUILD_DIR)/firmware.bin ## flash T1 core port on T1 using OpenOCD - $(OPENOCD_T1) -c "init; reset halt; flash write_image erase $< $(FIRMWARE_T1_START); exit" +else + $(OPENOCD) -c "init; reset halt; flash write_image erase $< $(FIRMWARE_START); exit" +endif flash_combine: $(PRODTEST_BUILD_DIR)/combined.bin ## flash combined using OpenOCD $(OPENOCD) -c "init; reset halt; flash write_image erase $< $(BOARDLOADER_START); exit" @@ -367,7 +377,11 @@ combine: ## combine boardloader + bootloader + prodtest into one combined image $(BOARDLOADER_BUILD_DIR)/boardloader.bin \ $(BOOTLOADER_BUILD_DIR)/bootloader.bin \ $(PRODTEST_BUILD_DIR)/prodtest.bin \ - $(PRODTEST_BUILD_DIR)/combined.bin + $(PRODTEST_BUILD_DIR)/combined.bin \ + $(BOARDLOADER_START) \ + $(BOARDLOADER_END) \ + $(BOOTLOADER_START) \ + $(PRODTEST_START) upload: ## upload firmware using trezorctl trezorctl firmware_update -s -f $(FIRMWARE_BUILD_DIR)/firmware.bin diff --git a/core/SConscript.boardloader b/core/SConscript.boardloader index 1efe8e1058..5ec7b873df 100644 --- a/core/SConscript.boardloader +++ b/core/SConscript.boardloader @@ -65,19 +65,21 @@ SOURCE_MOD += [ 'embed/lib/image.c', 'embed/lib/mini_printf.c', 'embed/lib/terminal.c', - 'vendor/trezor-storage/flash_common.c', - -] - -SOURCE_BOARDLOADER = [ - 'embed/boardloader/startup.s', - 'embed/boardloader/main.c', ] env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), CONSTRAINTS=["limited_util_s"]) 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_BOARDLOADER = [ + f"embed/boardloader/startup_{FILE_SUFFIX}.s", + 'embed/boardloader/main.c', +] + + env.Replace( CP='cp', AS='arm-none-eabi-as', @@ -104,7 +106,7 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS='-T embed/boardloader/memory.ld -Wl,--gc-sections -Wl,-Map=build/boardloader/boardloader.map -Wl,--warn-common -Wl,--print-memory-usage', + LINKFLAGS=f"-T embed/boardloader/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/boardloader/boardloader.map -Wl,--warn-common -Wl,--print-memory-usage", CPPPATH=[ 'embed/boardloader', 'embed/lib', @@ -161,7 +163,7 @@ program_bin = env.Command( target='boardloader.bin', source=program_elf, action=[ - '$OBJCOPY -O binary $SOURCE $TARGET', + '$OBJCOPY -O binary -j .vector_table -j .text -j .data -j .rodata -j .capabilities -j .sensitive $SOURCE $TARGET', '$CP $TARGET ' + BINARY_NAME, ], ) diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index d4e09291d2..a3e468d236 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -93,7 +93,6 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', 'vendor/micropython/lib/uzlib/tinflate.c', - 'vendor/trezor-storage/flash_common.c', ] SOURCE_NANOPB = [ @@ -102,15 +101,6 @@ SOURCE_NANOPB = [ 'vendor/nanopb/pb_encode.c', ] -SOURCE_BOOTLOADER = [ - 'embed/bootloader/startup.s', - 'embed/bootloader/header.S', - 'embed/bootloader/bootui.c', - 'embed/bootloader/main.c', - 'embed/bootloader/messages.c', - 'embed/bootloader/protob/messages.pb.c', -] - # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) @@ -122,6 +112,19 @@ env = Environment(ENV=os.environ, CFLAGS=f"{ARGUMENTS.get('CFLAGS', '')} -DPRODU 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_BOOTLOADER = [ + f'embed/bootloader/startup_{FILE_SUFFIX}.s', + 'embed/bootloader/header.S', + 'embed/bootloader/bootui.c', + 'embed/bootloader/main.c', + 'embed/bootloader/messages.c', + 'embed/bootloader/protob/messages.pb.c', +] + + env.Replace( CP='cp', AS='arm-none-eabi-as', @@ -148,7 +151,7 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS='-T embed/bootloader/memory.ld -Wl,--gc-sections -Wl,-Map=build/bootloader/bootloader.map -Wl,--warn-common -Wl,--print-memory-usage', + LINKFLAGS=f'-T embed/bootloader/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/bootloader/bootloader.map -Wl,--warn-common -Wl,--print-memory-usage', CPPPATH=[ 'embed/rust', 'embed/bootloader', @@ -267,7 +270,7 @@ program_bin = env.Command( target='bootloader.bin', source=program_elf, action=[ - '$OBJCOPY -O binary -j .header -j .flash -j .data $SOURCE $TARGET', + '$OBJCOPY -O binary -j .header -j .flash -j .data -j .sensitive $SOURCE $TARGET', '$HEADERTOOL $TARGET ' + ('-D' if not PRODUCTION else ''), '$CP $TARGET ' + BINARY_NAME, ], ) diff --git a/core/SConscript.bootloader_ci b/core/SConscript.bootloader_ci index b5824d357f..c6356f182b 100644 --- a/core/SConscript.bootloader_ci +++ b/core/SConscript.bootloader_ci @@ -66,7 +66,6 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/memzero.c', 'vendor/trezor-crypto/rand.c', 'vendor/trezor-crypto/sha2.c', - 'vendor/trezor-storage/flash_common.c', ] # modtrezorui @@ -94,16 +93,6 @@ SOURCE_NANOPB = [ 'vendor/nanopb/pb_encode.c', ] -SOURCE_BOOTLOADER = [ - 'embed/bootloader_ci/startup.s', - 'embed/bootloader_ci/header.S', - 'embed/bootloader_ci/bootui.c', - 'embed/bootloader_ci/main.c', - 'embed/bootloader_ci/messages.c', - 'embed/bootloader_ci/protob/messages.pb.c', -] - - # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) @@ -115,6 +104,18 @@ env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get(' 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_BOOTLOADER = [ + f'embed/bootloader_ci/startup_{FILE_SUFFIX}.s', + 'embed/bootloader_ci/header.S', + 'embed/bootloader_ci/bootui.c', + 'embed/bootloader_ci/main.c', + 'embed/bootloader_ci/messages.c', + 'embed/bootloader_ci/protob/messages.pb.c', +] + env.Replace( CP='cp', AS='arm-none-eabi-as', @@ -141,7 +142,7 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS='-T embed/bootloader_ci/memory.ld -Wl,--gc-sections -Wl,-Map=build/bootloader_ci/bootloader.map -Wl,--warn-common', + LINKFLAGS=f'-T embed/bootloader_ci/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/bootloader_ci/bootloader.map -Wl,--warn-common', CPPPATH=[ 'embed/bootloader_ci', 'embed/bootloader_ci/nanopb', @@ -209,7 +210,7 @@ program_bin = env.Command( target='bootloader.bin', source=program_elf, action=[ - '$OBJCOPY -O binary -j .header -j .flash -j .data $SOURCE $TARGET', + '$OBJCOPY -O binary -j .header -j .flash -j .data -j .sensitive $SOURCE $TARGET', '$HEADERTOOL $TARGET ' + ('-D' if ARGUMENTS.get('PRODUCTION', '0') == '0' else ''), '$CP $TARGET ' + BINARY_NAME, ], ) diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu index fb6b9aee72..2ea32755af 100644 --- a/core/SConscript.bootloader_emu +++ b/core/SConscript.bootloader_emu @@ -91,9 +91,13 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', 'vendor/micropython/lib/uzlib/tinflate.c', - 'vendor/trezor-storage/flash_common.c', ] +if TREZOR_MODEL in ('1', 'T', 'R', 'DISC1'): + SOURCE_MOD += [ + 'vendor/trezor-storage/flash_common_f4.c', + ] + if TREZOR_MODEL in ('1', ): SOURCE_MOD += [ 'embed/models/model_T1B1_layout.c', @@ -142,6 +146,8 @@ SOURCE_UNIX = [ 'embed/unix/profile.c', ] + + # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 469ca571b3..fa05d1e8f0 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -58,7 +58,6 @@ SOURCE_MOD += [ 'vendor/trezor-storage/norcow.c', 'vendor/trezor-storage/storage.c', 'vendor/trezor-storage/storage_utils.c', - 'vendor/trezor-storage/flash_common.c', ] # modtrezorcrypto @@ -345,16 +344,6 @@ SOURCE_MICROPYTHON_SPEED = [ 'vendor/micropython/py/vm.c', ] -SOURCE_FIRMWARE = [ - 'embed/firmware/bl_check.c', - 'embed/firmware/delay.c', - 'embed/firmware/header.S', - 'embed/firmware/main.c', - 'embed/firmware/mphalport.c', - 'embed/firmware/nlrthumb.c', - 'embed/firmware/startup.S', -] - CPPDEFINES_MOD += ['USE_SVC_SHUTDOWN'] if FEATURE_FLAGS["RDI"]: @@ -389,6 +378,18 @@ env = Environment(ENV=os.environ, CFLAGS=f"{ARGUMENTS.get('CFLAGS', '')} -DPRODU FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FILE_SUFFIX= env.get('ENV')['SUFFIX'] + +SOURCE_FIRMWARE = [ + 'embed/firmware/bl_check.c', + 'embed/firmware/delay.c', + 'embed/firmware/header.S', + 'embed/firmware/main.c', + 'embed/firmware/mphalport.c', + 'embed/firmware/nlrthumb.c', + f'embed/firmware/startup_{FILE_SUFFIX}.S', +] + if TREZOR_MODEL in ('T', 'DISC1'): UI_LAYOUT = 'UI_LAYOUT_TT' @@ -837,23 +838,31 @@ BINARY_NAME += "-dirty" if tools.get_git_modified() else "" BINARY_NAME += ".bin" -if TREZOR_MODEL in ('T', 'R', 'DISC1'): + +if TREZOR_MODEL in ('1',): action_bin=[ - '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data --pad-to 0x08100000 $SOURCE ${TARGET}.p1', - '$OBJCOPY -O binary -j .flash2 $SOURCE ${TARGET}.p2', - '$CAT ${TARGET}.p1 ${TARGET}.p2 > $TARGET', - '$HEADERTOOL -h $TARGET ' + ('-D' if not PRODUCTION else ''), - '$DD if=$TARGET of=${TARGET}.p1 skip=0 bs=128k count=6', - '$CP $TARGET ' + BINARY_NAME, - ] -elif TREZOR_MODEL in ('1',): - action_bin=[ - '$OBJCOPY -O binary -j .header -j .flash -j .data $SOURCE $TARGET', + '$OBJCOPY -O binary -j .header -j .flash -j .data -j .sensitive $SOURCE $TARGET', '../legacy/bootloader/firmware_sign.py -f $TARGET', '$CP $TARGET ' + BINARY_NAME, ] else: - raise ValueError('Unknown Trezor model') + if 'STM32F427xx' in CPPDEFINES_HAL or 'STM32F429xx' in CPPDEFINES_HAL: + action_bin=[ + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .sensitive --pad-to 0x08100000 $SOURCE ${TARGET}.p1', + '$OBJCOPY -O binary -j .flash2 $SOURCE ${TARGET}.p2', + '$CAT ${TARGET}.p1 ${TARGET}.p2 > $TARGET', + '$HEADERTOOL -h $TARGET ' + ('-D' if not PRODUCTION else ''), + '$DD if=$TARGET of=${TARGET}.p1 skip=0 bs=128k count=6', + '$CP $TARGET ' + BINARY_NAME, + ] + elif 'STM32U5A9xx' in CPPDEFINES_HAL: + action_bin=[ + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .sensitive $SOURCE ${TARGET}', + '$HEADERTOOL -h $TARGET ' + ('-D' if not PRODUCTION else ''), + '$CP $TARGET ' + BINARY_NAME, + ] + else: + raise Exception("Unknown MCU") program_bin = env.Command( target='firmware.bin', diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index 5bf315edb4..7b6ae62070 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -91,21 +91,8 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', 'vendor/micropython/lib/uzlib/tinflate.c', - 'vendor/trezor-storage/flash_common.c', ] -SOURCE_PRODTEST = [ - 'embed/prodtest/startup.s', - 'embed/prodtest/header.S', - 'embed/prodtest/main.c', - 'embed/prodtest/prodtest_common.c', -] - -if TREZOR_MODEL in ('R',): - SOURCE_PRODTEST += [ - 'embed/prodtest/optiga_prodtest.c', - ] - # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) @@ -117,6 +104,22 @@ env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get(' 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_PRODTEST = [ + f'embed/prodtest/startup_{FILE_SUFFIX}.s', + 'embed/prodtest/header.S', + 'embed/prodtest/main.c', + 'embed/prodtest/prodtest_common.c', +] + +if 'optiga' in FEATURES_AVAILABLE: + SOURCE_PRODTEST += [ + 'embed/prodtest/optiga_prodtest.c', + ] + env.Replace( CP='cp', AS='arm-none-eabi-as', @@ -143,7 +146,7 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS='-T embed/prodtest/memory.ld -Wl,--gc-sections -Wl,-Map=build/prodtest/prodtest.map -Wl,--warn-common', + LINKFLAGS=f'-T embed/prodtest/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/prodtest/prodtest.map -Wl,--warn-common', CPPPATH=[ 'embed/prodtest', 'embed/lib', @@ -225,7 +228,7 @@ program_bin = env.Command( target='prodtest.bin', source=program_elf, action=[ - '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET', + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .sensitive $SOURCE $TARGET', '$HEADERTOOL $TARGET ' + ('-D' if ARGUMENTS.get('PRODUCTION', '0') == '0' else ''), '$CP $TARGET ' + BINARY_NAME, ], ) diff --git a/core/SConscript.reflash b/core/SConscript.reflash index 27afdbae2c..d6b23479cc 100644 --- a/core/SConscript.reflash +++ b/core/SConscript.reflash @@ -65,13 +65,6 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', 'vendor/micropython/lib/uzlib/tinflate.c', - 'vendor/trezor-storage/flash_common.c', -] - -SOURCE_REFLASH = [ - 'embed/reflash/startup.s', - 'embed/reflash/header.S', - 'embed/reflash/main.c', ] # fonts @@ -85,6 +78,15 @@ env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get(' 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_REFLASH = [ + f'embed/reflash/startup_{FILE_SUFFIX}.s', + 'embed/reflash/header.S', + 'embed/reflash/main.c', +] + env.Replace( CP='cp', AS='arm-none-eabi-as', @@ -111,7 +113,7 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS='-T embed/reflash/memory.ld -Wl,--gc-sections -Wl,-Map=build/reflash/reflash.map -Wl,--warn-common', + LINKFLAGS=f'-T embed/reflash/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/reflash/reflash.map -Wl,--warn-common', CPPPATH=[ 'embed/reflash', 'embed/lib', @@ -182,7 +184,7 @@ program_bin = env.Command( target='reflash.bin', source=program_elf, action=[ - '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET', + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .sensitive $SOURCE $TARGET', '$HEADERTOOL $TARGET ' + ('-D' if ARGUMENTS.get('PRODUCTION', '0') == '0' else ''), '$CP $TARGET ' + BINARY_NAME, ], ) diff --git a/core/SConscript.unix b/core/SConscript.unix index fe74a5865d..b292dbe1c8 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -59,9 +59,13 @@ SOURCE_MOD += [ 'vendor/trezor-storage/norcow.c', 'vendor/trezor-storage/storage.c', 'vendor/trezor-storage/storage_utils.c', - 'vendor/trezor-storage/flash_common.c', ] +if TREZOR_MODEL in ('1', 'T', 'R', 'DISC1'): + SOURCE_MOD += [ + 'vendor/trezor-storage/flash_common_f4.c', + ] + # modtrezorcrypto CCFLAGS_MOD += '-Wno-sequence-point ' CPPPATH_MOD += [ diff --git a/core/embed/boardloader/.changelog.d/3370.added b/core/embed/boardloader/.changelog.d/3370.added new file mode 100644 index 0000000000..20f7c86466 --- /dev/null +++ b/core/embed/boardloader/.changelog.d/3370.added @@ -0,0 +1 @@ +Added basic support for STM32U5 diff --git a/core/embed/boardloader/main.c b/core/embed/boardloader/main.c index 0e58b08582..fd147f4e15 100644 --- a/core/embed/boardloader/main.c +++ b/core/embed/boardloader/main.c @@ -27,8 +27,10 @@ #include "flash.h" #include "image.h" #include "model.h" +#include "mpu.h" #include "rng.h" #include "terminal.h" + #ifdef USE_SD_CARD #include "sdcard.h" #endif @@ -42,6 +44,12 @@ #include "memzero.h" +#ifdef STM32U5 +#include "secret.h" +#include "tamper.h" +#include "trustzone.h" +#endif + const uint8_t BOARDLOADER_KEY_M = 2; const uint8_t BOARDLOADER_KEY_N = 3; static const uint8_t * const BOARDLOADER_KEYS[] = { @@ -54,6 +62,44 @@ static const uint8_t * const BOARDLOADER_KEYS[] = { #endif }; +#ifdef STM32U5 +void check_bootloader_version(uint8_t bld_version) { + const uint8_t *counter_addr = + flash_area_get_address(&SECRET_AREA, SECRET_MONOTONIC_COUNTER_OFFSET, + SECRET_MONOTONIC_COUNTER_LEN); + + ensure((counter_addr != NULL) * sectrue, "counter_addr is NULL"); + + int counter = 0; + + for (int i = 0; i < SECRET_MONOTONIC_COUNTER_LEN / 16; i++) { + secbool not_cleared = sectrue; + for (int j = 0; j < 16; j++) { + if (counter_addr[i * 16 + j] != 0xFF) { + not_cleared = secfalse; + break; + } + } + + if (not_cleared != sectrue) { + counter++; + } else { + break; + } + } + + ensure((bld_version >= counter) * sectrue, "BOOTLOADER DOWNGRADED"); + + if (bld_version > counter) { + for (int i = 0; i < bld_version; i++) { + uint32_t data[4] = {0}; + secret_write((uint8_t *)data, SECRET_MONOTONIC_COUNTER_OFFSET + i * 16, + 16); + } + } +} +#endif + struct BoardCapabilities capablities __attribute__((section(".capabilities_section"))) = { .header = CAPABILITIES_HEADER, @@ -194,12 +240,30 @@ int main(void) { return 2; } +#ifdef STM32U5 + tamper_init(); + + if (sectrue == secret_bhk_locked()) { + delete_secrets(); + NVIC_SystemReset(); + } +#endif + +#ifdef STM32F4 clear_otg_hs_memory(); +#endif + + mpu_config_boardloader(); #ifdef USE_SDRAM sdram_init(); #endif +#ifdef STM32U5 + trustzone_init(); + trustzone_run(); +#endif + display_init(); display_clear(); @@ -225,8 +289,15 @@ int main(void) { ensure(check_image_contents(hdr, IMAGE_HEADER_SIZE, &BOOTLOADER_AREA), "invalid bootloader hash"); +#ifdef STM32U5 + check_bootloader_version(hdr->monotonic); +#endif + ensure_compatible_settings(); + mpu_config_off(); + + // g_boot_flag is preserved on STM32U5 jump_to(BOOTLOADER_START + IMAGE_HEADER_SIZE); return 0; diff --git a/core/embed/boardloader/memory.ld b/core/embed/boardloader/memory_stm32f4.ld similarity index 100% rename from core/embed/boardloader/memory.ld rename to core/embed/boardloader/memory_stm32f4.ld diff --git a/core/embed/boardloader/memory_stm32u5a.ld b/core/embed/boardloader/memory_stm32u5a.ld new file mode 100644 index 0000000000..40aea090cd --- /dev/null +++ b/core/embed/boardloader/memory_stm32u5a.ld @@ -0,0 +1,109 @@ +/* Trezor v2 boardloader linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C004000, LENGTH = 48K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - (0x100 + 4) + BOOT_ARGS (wal) : ORIGIN = 0x300BFEFC, LENGTH = (0x100 + 4) + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 0K /* 512K on U5G */ + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2) + 0x100; +_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); +g_boot_args = (boot_args_start + 4); +g_boot_flag = boot_args_start; + +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 + 0x100; /* Exactly 16K allocated for stack. Overflow causes MemManage fault (when using MPU). */ + } >SRAM2 + + .sensitive : ALIGN(8) { + *(.sensitive*); + . = ALIGN(4); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 + + /* Hard-coded address for capabilities structure */ + .capabilities 0x0C00FF00 : {KEEP(*(.capabilities_section))} +} diff --git a/core/embed/boardloader/startup.s b/core/embed/boardloader/startup_stm32f4.s similarity index 100% rename from core/embed/boardloader/startup.s rename to core/embed/boardloader/startup_stm32f4.s diff --git a/core/embed/boardloader/startup_stm32u5.s b/core/embed/boardloader/startup_stm32u5.s new file mode 100644 index 0000000000..fa61c0cc54 --- /dev/null +++ b/core/embed/boardloader/startup_stm32u5.s @@ -0,0 +1,102 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + 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 diff --git a/core/embed/bootloader/.changelog.d/3370.added b/core/embed/bootloader/.changelog.d/3370.added new file mode 100644 index 0000000000..20f7c86466 --- /dev/null +++ b/core/embed/bootloader/.changelog.d/3370.added @@ -0,0 +1 @@ +Added basic support for STM32U5 diff --git a/core/embed/bootloader/emulator.c b/core/embed/bootloader/emulator.c index c304d75dc1..36d885a9fe 100644 --- a/core/embed/bootloader/emulator.c +++ b/core/embed/bootloader/emulator.c @@ -28,7 +28,8 @@ void set_core_clock(int) {} int bootloader_main(void); -bool sector_is_empty(const flash_area_t *area) { +// assuming storage is single subarea +bool storage_empty(const flash_area_t *area) { const uint8_t *storage = flash_area_get_address(area, 0, 0); size_t storage_size = flash_area_get_size(area); for (size_t i = 0; i < storage_size; i++) { @@ -117,7 +118,7 @@ __attribute__((noreturn)) int main(int argc, char **argv) { FIRMWARE_START = (uint8_t *)flash_area_get_address(&FIRMWARE_AREA, 0, 0); // simulate non-empty storage so that we know whether it was erased or not - if (sector_is_empty(&STORAGE_AREAS[0])) { + if (storage_empty(&STORAGE_AREAS[0])) { secbool ret = flash_area_write_word(&STORAGE_AREAS[0], 16, 0x12345678); (void)ret; } @@ -197,7 +198,7 @@ void mpu_config_off(void) {} __attribute__((noreturn)) void jump_to(void *addr) { bool storage_is_erased = - sector_is_empty(&STORAGE_AREAS[0]) && sector_is_empty(&STORAGE_AREAS[1]); + storage_empty(&STORAGE_AREAS[0]) && storage_empty(&STORAGE_AREAS[1]); if (storage_is_erased) { printf("STORAGE WAS ERASED\n"); diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index f9fed5cc0f..677e87bc4d 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -23,8 +23,10 @@ #include "boot_internal.h" #include "common.h" #include "display.h" +#include "display_utils.h" #include "flash.h" #include "image.h" +#include "lowlevel.h" #include "messages.pb.h" #include "random_delays.h" #include "secbool.h" @@ -77,9 +79,10 @@ typedef enum { RETURN_TO_MENU = 0x55667788, } usb_result_t; -volatile secbool dont_optimize_out_true = sectrue; void failed_jump_to_firmware(void); -volatile void (*firmware_jump_fn)(void) = failed_jump_to_firmware; + +SENSITIVE volatile secbool dont_optimize_out_true = sectrue; +SENSITIVE volatile void (*firmware_jump_fn)(void) = failed_jump_to_firmware; static void usb_init_all(secbool usb21_landing) { usb_dev_info_t dev_info = { @@ -214,7 +217,7 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, case MessageType_MessageType_GetFeatures: process_msg_GetFeatures(USB_IFACE_NUM, msg_size, buf, vhdr, hdr); break; -#ifdef USE_OPTIGA +#if defined USE_OPTIGA && !defined STM32U5 case MessageType_MessageType_UnlockBootloader: response = ui_screen_unlock_bootloader_confirm(); if (INPUT_CANCEL == response) { @@ -258,7 +261,7 @@ static secbool check_vendor_header_lock(const vendor_header *const vhdr) { // protection against bootloader downgrade -#if PRODUCTION +#if PRODUCTION && !defined STM32U5 static void check_bootloader_version(void) { uint8_t bits[FLASH_OTP_BLOCK_SIZE]; @@ -317,11 +320,30 @@ void real_jump_to_firmware(void) { &FIRMWARE_AREA), "Firmware is corrupted"); +#ifdef STM32U5 + secret_bhk_provision(); + secret_bhk_lock(); #ifdef USE_OPTIGA + if (sectrue == secret_optiga_present()) { + secret_optiga_backup(); + secret_hide(); + } +#else + secret_hide(); +#endif +#endif + +#ifdef USE_OPTIGA +#ifdef STM32U5 + if ((vhdr.vtrust & VTRUST_SECRET) != 0) { + secret_optiga_hide(); + } +#else if (((vhdr.vtrust & VTRUST_SECRET) != 0) && (sectrue != secret_wiped())) { ui_screen_install_restricted(); trezor_shutdown(); } +#endif #endif // if all VTRUST flags are unset = ultimate trust => skip the procedure @@ -357,6 +379,18 @@ void real_jump_to_firmware(void) { jump_to(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE); } +#ifdef STM32U5 +__attribute__((noreturn)) void jump_to_fw_through_reset(void) { + display_fade(display_backlight(-1), 0, 200); + + __disable_irq(); + delete_secrets(); + NVIC_SystemReset(); + for (;;) + ; +} +#endif + #ifndef TREZOR_EMULATOR int main(void) { #else @@ -365,7 +399,21 @@ int bootloader_main(void) { secbool stay_in_bootloader = secfalse; random_delays_init(); - // display_init_seq(); + +#ifdef STM32U5 + if (sectrue != flash_configure_sec_area_ob()) { +#ifdef STM32U5 + secret_bhk_regenerate(); +#endif + + const secbool r = + flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL); + (void)r; + __disable_irq(); + HAL_NVIC_SystemReset(); + } +#endif + #ifdef USE_DMA2D dma2d_init(); #endif @@ -460,7 +508,8 @@ int bootloader_main(void) { unit_variant_init(); -#if PRODUCTION +#if PRODUCTION && !defined STM32U5 + // for STM32U5, this check is moved to boardloader check_bootloader_version(); #endif @@ -529,6 +578,9 @@ int bootloader_main(void) { } else { screen = SCREEN_WELCOME; +#ifdef STM32U5 + secret_bhk_regenerate(); +#endif // erase storage ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), NULL); @@ -583,7 +635,9 @@ int bootloader_main(void) { screen = SCREEN_INTRO; } if (ui_result == 0x11223344) { // reboot +#ifndef STM32U5 ui_screen_boot_empty(true); +#endif continue_to_firmware = firmware_present; continue_to_firmware_backup = firmware_present_backup; } @@ -633,6 +687,10 @@ int bootloader_main(void) { if (continue_to_firmware != continue_to_firmware_backup) { // erase storage if we saw flips randomly flip, most likely due to // glitch + +#ifdef STM32U5 + secret_bhk_regenerate(); +#endif ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), NULL); } @@ -640,7 +698,11 @@ int bootloader_main(void) { (continue_to_firmware == continue_to_firmware_backup), NULL); if (sectrue == continue_to_firmware) { +#ifdef STM32U5 + firmware_jump_fn = jump_to_fw_through_reset; +#else firmware_jump_fn = real_jump_to_firmware; +#endif break; } } @@ -648,13 +710,19 @@ int bootloader_main(void) { ensure(dont_optimize_out_true * (firmware_present == firmware_present_backup), NULL); + +#ifdef STM32U5 + if (sectrue == firmware_present && + firmware_jump_fn != jump_to_fw_through_reset) { + firmware_jump_fn = real_jump_to_firmware; + } +#else if (sectrue == firmware_present) { firmware_jump_fn = real_jump_to_firmware; } +#endif firmware_jump_fn(); return 0; } - -void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(HF)"); } diff --git a/core/embed/bootloader/memory.ld b/core/embed/bootloader/memory_stm32f4.ld similarity index 96% rename from core/embed/bootloader/memory.ld rename to core/embed/bootloader/memory_stm32f4.ld index b96888c7e5..d20e58cec1 100644 --- a/core/embed/bootloader/memory.ld +++ b/core/embed/bootloader/memory_stm32f4.ld @@ -10,6 +10,8 @@ MEMORY { } main_stack_base = ORIGIN(CCMRAM) + SIZEOF(.stack) ; /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(CCMRAM); +_estack = main_stack_base; /* used by the startup code to populate variables used by the C code */ data_lma = LOADADDR(.data); diff --git a/core/embed/bootloader/memory_stm32u5a.ld b/core/embed/bootloader/memory_stm32u5a.ld new file mode 100644 index 0000000000..9a0df820d1 --- /dev/null +++ b/core/embed/bootloader/memory_stm32u5a.ld @@ -0,0 +1,107 @@ +/* Trezor v2 bootloader linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C010000, LENGTH = 128K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - (0x100 + 4) + BOOT_ARGS (wal) : ORIGIN = 0x300BFEFC, LENGTH = (0x100 + 4) + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 0 + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2) + 0x100; +_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); +g_boot_args = (boot_args_start + 4); +g_boot_flag = boot_args_start; + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); + +SECTIONS { + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K + 0x100; /* Exactly 16K allocated for stack. Overflow causes MemManage fault (when using MPU). */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 +} diff --git a/core/embed/bootloader/messages.c b/core/embed/bootloader/messages.c index 040326be34..b1e5980ccd 100644 --- a/core/embed/bootloader/messages.c +++ b/core/embed/bootloader/messages.c @@ -637,7 +637,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, is_ilu = sectrue; } -#ifdef USE_OPTIGA +#if defined USE_OPTIGA && !defined STM32U5 if (sectrue != secret_wiped() && ((vhdr.vtrust & VTRUST_SECRET) != 0)) { MSG_SEND_INIT(Failure); MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); @@ -666,6 +666,9 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, // if firmware is not upgrade, erase storage if (sectrue != should_keep_seed) { +#ifdef STM32U5 + secret_bhk_regenerate(); +#endif ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), NULL); } @@ -834,7 +837,7 @@ void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { MSG_SEND(Failure); } -#ifdef USE_OPTIGA +#if defined USE_OPTIGA && !defined STM32U5 void process_msg_UnlockBootloader(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { secret_erase(); diff --git a/core/embed/bootloader/startup.s b/core/embed/bootloader/startup_stm32f4.s similarity index 100% rename from core/embed/bootloader/startup.s rename to core/embed/bootloader/startup_stm32f4.s diff --git a/core/embed/bootloader/startup_stm32u5.s b/core/embed/bootloader/startup_stm32u5.s new file mode 100644 index 0000000000..858f2694f4 --- /dev/null +++ b/core/embed/bootloader/startup_stm32u5.s @@ -0,0 +1,78 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // setup environment for subsequent stage of code + 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, =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, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_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, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_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] + + // + ldr r0, =g_boot_flag + ldr r1, [r0] + ldr r0, =g_boot_command + str r1, [r0] + ldr r0, =g_boot_flag + mov r1, #0 + str r1, [r0] + + // re-enable exceptions + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: + // "If it is not necessary to ensure that a pended interrupt is recognized immediately before + // subsequent operations, it is not necessary to insert a memory barrier instruction." + cpsie f + + // enter the application code + bl main + + b shutdown_privileged + + .bss + + .global g_boot_command +g_boot_command: + .word 0 + + .end diff --git a/core/embed/bootloader_ci/.changelog.d/3370.added b/core/embed/bootloader_ci/.changelog.d/3370.added new file mode 100644 index 0000000000..20f7c86466 --- /dev/null +++ b/core/embed/bootloader_ci/.changelog.d/3370.added @@ -0,0 +1 @@ +Added basic support for STM32U5 diff --git a/core/embed/bootloader_ci/memory.ld b/core/embed/bootloader_ci/memory_stm32f4.ld similarity index 78% rename from core/embed/bootloader_ci/memory.ld rename to core/embed/bootloader_ci/memory_stm32f4.ld index 8a05c75c46..081bb05116 100644 --- a/core/embed/bootloader_ci/memory.ld +++ b/core/embed/bootloader_ci/memory_stm32f4.ld @@ -9,7 +9,9 @@ MEMORY { SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 192K } -main_stack_base = ORIGIN(CCMRAM) + LENGTH(CCMRAM); /* 8-byte aligned full descending stack */ +main_stack_base = ORIGIN(CCMRAM) + SIZEOF(.stack) ; /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(CCMRAM); +_estack = main_stack_base; /* used by the startup code to populate variables used by the C code */ data_lma = LOADADDR(.data); @@ -44,17 +46,27 @@ SECTIONS { . = ALIGN(512); } >FLASH AT>FLASH + .stack : ALIGN(8) { + . = 16K; /* Exactly 16K allocated for stack. Overflow causes MemManage fault (when using MPU). */ + } >CCMRAM + .data : ALIGN(4) { *(.data*); . = ALIGN(512); } >CCMRAM AT>FLASH + /DISCARD/ : { + *(.ARM.exidx*); + } + .bss : ALIGN(4) { *(.bss*); . = ALIGN(4); } >CCMRAM - .stack : ALIGN(8) { - . = 4K; /* this acts as a build time assertion that at least this much memory is available for stack use */ - } >CCMRAM + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM + } diff --git a/core/embed/bootloader_ci/memory_stm32u5a.ld b/core/embed/bootloader_ci/memory_stm32u5a.ld new file mode 100644 index 0000000000..9a0df820d1 --- /dev/null +++ b/core/embed/bootloader_ci/memory_stm32u5a.ld @@ -0,0 +1,107 @@ +/* Trezor v2 bootloader linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C010000, LENGTH = 128K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - (0x100 + 4) + BOOT_ARGS (wal) : ORIGIN = 0x300BFEFC, LENGTH = (0x100 + 4) + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 0 + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2) + 0x100; +_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); +g_boot_args = (boot_args_start + 4); +g_boot_flag = boot_args_start; + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); + +SECTIONS { + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K + 0x100; /* Exactly 16K allocated for stack. Overflow causes MemManage fault (when using MPU). */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 +} diff --git a/core/embed/bootloader_ci/startup.s b/core/embed/bootloader_ci/startup_stm32f4.s similarity index 100% rename from core/embed/bootloader_ci/startup.s rename to core/embed/bootloader_ci/startup_stm32f4.s diff --git a/core/embed/bootloader_ci/startup_stm32u5.s b/core/embed/bootloader_ci/startup_stm32u5.s new file mode 100644 index 0000000000..858f2694f4 --- /dev/null +++ b/core/embed/bootloader_ci/startup_stm32u5.s @@ -0,0 +1,78 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // setup environment for subsequent stage of code + 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, =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, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_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, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_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] + + // + ldr r0, =g_boot_flag + ldr r1, [r0] + ldr r0, =g_boot_command + str r1, [r0] + ldr r0, =g_boot_flag + mov r1, #0 + str r1, [r0] + + // re-enable exceptions + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: + // "If it is not necessary to ensure that a pended interrupt is recognized immediately before + // subsequent operations, it is not necessary to insert a memory barrier instruction." + cpsie f + + // enter the application code + bl main + + b shutdown_privileged + + .bss + + .global g_boot_command +g_boot_command: + .word 0 + + .end diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index f21fdeac8b..d4ae27b806 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -48,6 +48,7 @@ #include "mpu.h" #include "random_delays.h" #include "rust_ui.h" +#include "secure_aes.h" #include TREZOR_BOARD @@ -75,8 +76,11 @@ #ifdef USE_OPTIGA #include "optiga_commands.h" #include "optiga_transport.h" +#endif +#if defined USE_OPTIGA | defined STM32U5 #include "secret.h" #endif + #include "unit_variant.h" #ifdef SYSTEM_VIEW @@ -99,6 +103,10 @@ int main(void) { rdi_start(); #endif +#ifdef STM32U5 + check_oem_keys(); +#endif + // reinitialize HAL for Trezor One #if defined TREZOR_MODEL_1 HAL_Init(); @@ -125,8 +133,7 @@ int main(void) { #ifdef USE_OPTIGA uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0}; - secbool secret_ok = - secret_read(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); + secbool secret_ok = secret_optiga_extract(secret); #endif #if PRODUCTION || BOOTLOADER_QA @@ -148,6 +155,10 @@ int main(void) { set_core_clock(CLOCK_180_MHZ); #endif +#ifdef STM32U5 + secure_aes_init(); +#endif + #ifdef USE_BUTTON button_init(); #endif @@ -231,25 +242,6 @@ void __attribute__((noreturn)) nlr_jump_fail(void *val) { error_shutdown("INTERNAL ERROR", "(UE)"); } -// interrupt handlers - -void NMI_Handler(void) { - // Clock Security System triggered NMI - if ((RCC->CIR & RCC_CIR_CSSF) != 0) { - error_shutdown("INTERNAL ERROR", "(CS)"); - } -} - -void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(HF)"); } - -void MemManage_Handler_MM(void) { error_shutdown("INTERNAL ERROR", "(MM)"); } - -void MemManage_Handler_SO(void) { error_shutdown("INTERNAL ERROR", "(SO)"); } - -void BusFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(BF)"); } - -void UsageFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(UF)"); } - // MicroPython builtin stubs mp_import_stat_t mp_import_stat(const char *path) { diff --git a/core/embed/firmware/memory_T.ld b/core/embed/firmware/memory_T.ld index fa557dccd1..d0a489b4cb 100644 --- a/core/embed/firmware/memory_T.ld +++ b/core/embed/firmware/memory_T.ld @@ -26,6 +26,7 @@ ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); +g_boot_args = boot_args_start; /* used by the startup code to wipe memory */ sram_start = ORIGIN(SRAM); diff --git a/core/embed/firmware/startup.S b/core/embed/firmware/startup_stm32f4.S similarity index 90% rename from core/embed/firmware/startup.S rename to core/embed/firmware/startup_stm32f4.S index dbed46bb25..7d0fadf2cd 100644 --- a/core/embed/firmware/startup.S +++ b/core/embed/firmware/startup_stm32f4.S @@ -66,16 +66,4 @@ reset_handler: b shutdown_privileged - .global MemManage_Handler - .type MemManage_Handler, STT_FUNC -MemManage_Handler: - ldr r2, =_sstack - mrs r1, msp - ldr r0, =_estack - msr msp, r0 - cmp r1, r2 - IT lt - bllt MemManage_Handler_SO - bl MemManage_Handler_MM - .end diff --git a/core/embed/firmware/startup_stm32u5.S b/core/embed/firmware/startup_stm32u5.S new file mode 100644 index 0000000000..3c10235961 --- /dev/null +++ b/core/embed/firmware/startup_stm32u5.S @@ -0,0 +1,67 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // setup environment for subsequent stage of code + 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, =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, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_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] + + // re-enable exceptions + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: + // "If it is not necessary to ensure that a pended interrupt is recognized immediately before + // subsequent operations, it is not necessary to insert a memory barrier instruction." + cpsie f + + // enter the application code + bl main + + b shutdown_privileged + + .end diff --git a/core/embed/trezorhal/stm32f4/compiler_traits.h b/core/embed/lib/compiler_traits.h similarity index 100% rename from core/embed/trezorhal/stm32f4/compiler_traits.h rename to core/embed/lib/compiler_traits.h diff --git a/core/embed/models/layout_common.h b/core/embed/models/layout_common.h index 898338eeb5..47e50583c6 100644 --- a/core/embed/models/layout_common.h +++ b/core/embed/models/layout_common.h @@ -15,6 +15,7 @@ extern const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT]; extern const flash_area_t BOARDLOADER_AREA; extern const flash_area_t SECRET_AREA; +extern const flash_area_t BHK_AREA; extern const flash_area_t TRANSLATIONS_AREA; extern const flash_area_t BOOTLOADER_AREA; extern const flash_area_t FIRMWARE_AREA; diff --git a/core/embed/models/model_D001.h b/core/embed/models/model_D001.h index 15350cbd55..def874fc33 100644 --- a/core/embed/models/model_D001.h +++ b/core/embed/models/model_D001.h @@ -19,6 +19,7 @@ (const uint8_t *)"\xee\x93\xa4\xf6\x6f\x8d\x16\xb8\x19\xbb\x9b\xeb\x9f\xfc\xcd\xfc\xdc\x14\x12\xe8\x7f\xee\x6a\x32\x4c\x2a\x99\xa1\xe0\xe6\x71\x48", #define BOARDLOADER_START 0x08000000 +#define BOARD_CAPABILITIES_ADDR 0x0800BF00 #define BOOTLOADER_START 0x08020000 #define FIRMWARE_START 0x08040000 diff --git a/core/embed/models/model_T2B1.h b/core/embed/models/model_T2B1.h index 3e996ae917..460bb372cd 100644 --- a/core/embed/models/model_T2B1.h +++ b/core/embed/models/model_T2B1.h @@ -19,6 +19,7 @@ (const uint8_t *)"\x07\xc8\x51\x34\x94\x6b\xf8\x9f\xa1\x9b\xdc\x2c\x5e\x5f\xf9\xce\x01\x29\x65\x08\xee\x08\x63\xd0\xff\x6d\x63\x33\x1d\x1a\x25\x16", #define BOARDLOADER_START 0x08000000 +#define BOARD_CAPABILITIES_ADDR 0x0800BF00 #define BOOTLOADER_START 0x08020000 #define FIRMWARE_START 0x08040000 diff --git a/core/embed/models/model_T2T1.h b/core/embed/models/model_T2T1.h index 5a98e7cafb..d632951d00 100644 --- a/core/embed/models/model_T2T1.h +++ b/core/embed/models/model_T2T1.h @@ -19,6 +19,7 @@ (const uint8_t *)"\xb8\x30\x7a\x71\xf5\x52\xc6\x0a\x4c\xbb\x31\x7f\xf4\x8b\x82\xcd\xbf\x6b\x6b\xb5\xf0\x4c\x92\x0f\xec\x7b\xad\xf0\x17\x88\x37\x51", #define BOARDLOADER_START 0x08000000 +#define BOARD_CAPABILITIES_ADDR 0x0800BF00 #define BOOTLOADER_START 0x08020000 #define FIRMWARE_START 0x08040000 diff --git a/core/embed/prodtest/.changelog.d/3370.added b/core/embed/prodtest/.changelog.d/3370.added new file mode 100644 index 0000000000..20f7c86466 --- /dev/null +++ b/core/embed/prodtest/.changelog.d/3370.added @@ -0,0 +1 @@ +Added basic support for STM32U5 diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c index a9416624dd..97cdc80bb6 100644 --- a/core/embed/prodtest/main.c +++ b/core/embed/prodtest/main.c @@ -669,5 +669,3 @@ int main(void) { return 0; } - -void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(HF)"); } diff --git a/core/embed/prodtest/memory.ld b/core/embed/prodtest/memory_stm32f4.ld similarity index 98% rename from core/embed/prodtest/memory.ld rename to core/embed/prodtest/memory_stm32f4.ld index afbe0aa3bb..0bc567ca29 100644 --- a/core/embed/prodtest/memory.ld +++ b/core/embed/prodtest/memory_stm32f4.ld @@ -10,6 +10,7 @@ MEMORY { } main_stack_base = ORIGIN(SRAM) + LENGTH(SRAM); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM); _estack = main_stack_base; /* used by the startup code to populate variables used by the C code */ diff --git a/core/embed/prodtest/memory_stm32u5a.ld b/core/embed/prodtest/memory_stm32u5a.ld new file mode 100644 index 0000000000..82e177b7ad --- /dev/null +++ b/core/embed/prodtest/memory_stm32u5a.ld @@ -0,0 +1,123 @@ +/* TREZORv2 firmware linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - (0x100 + 4) + BOOT_ARGS (wal) : ORIGIN = 0x300BFEFC, LENGTH = (0x100 + 4) + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 0 + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2) + 0x100; +_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); +g_boot_args = (boot_args_start + 4); +g_boot_flag= boot_args_start; + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); +_heap_start = ADDR(.heap); +_heap_end = ADDR(.heap) + SIZEOF(.heap); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .data_ccm : ALIGN(4) { + *(.no_dma_buffers*); + . = ALIGN(4); + } >SRAM1 + + .heap : ALIGN(4) { + . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ + . = ABSOLUTE(sram1_end); /* this explicitly sets the end of the heap */ + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K + 0x100; /* Exactly 16K allocated for stack. Overflow causes MemManage fault (when using MPU). */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 +} diff --git a/core/embed/prodtest/startup.s b/core/embed/prodtest/startup_stm32f4.s similarity index 100% rename from core/embed/prodtest/startup.s rename to core/embed/prodtest/startup_stm32f4.s diff --git a/core/embed/prodtest/startup_stm32u5.s b/core/embed/prodtest/startup_stm32u5.s new file mode 100644 index 0000000000..3c10235961 --- /dev/null +++ b/core/embed/prodtest/startup_stm32u5.s @@ -0,0 +1,67 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // setup environment for subsequent stage of code + 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, =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, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_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] + + // re-enable exceptions + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: + // "If it is not necessary to ensure that a pended interrupt is recognized immediately before + // subsequent operations, it is not necessary to insert a memory barrier instruction." + cpsie f + + // enter the application code + bl main + + b shutdown_privileged + + .end diff --git a/core/embed/reflash/memory.ld b/core/embed/reflash/memory_stm32f4.ld similarity index 100% rename from core/embed/reflash/memory.ld rename to core/embed/reflash/memory_stm32f4.ld diff --git a/core/embed/reflash/memory_stm32u5a.ld b/core/embed/reflash/memory_stm32u5a.ld new file mode 100644 index 0000000000..a57655ac32 --- /dev/null +++ b/core/embed/reflash/memory_stm32u5a.ld @@ -0,0 +1,123 @@ +/* TREZORv2 firmware linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - (0x100 + 4) + BOOT_ARGS (wal) : ORIGIN = 0x300BFEFC, LENGTH = (0x100 + 4) + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 512K + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2) + 0x100; +_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); +g_boot_args = (boot_args_start + 4); +g_boot_flag = boot_args_start; + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); +_heap_start = ADDR(.heap); +_heap_end = ADDR(.heap) + SIZEOF(.heap); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .data_ccm : ALIGN(4) { + *(.no_dma_buffers*); + . = ALIGN(4); + } >SRAM1 + + .heap : ALIGN(4) { + . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ + . = ABSOLUTE(sram1_end); /* this explicitly sets the end of the heap */ + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K + 0x100; /* Exactly 16K allocated for stack. Overflow causes MemManage fault (when using MPU). */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 +} diff --git a/core/embed/reflash/startup.s b/core/embed/reflash/startup_stm32f4.s similarity index 100% rename from core/embed/reflash/startup.s rename to core/embed/reflash/startup_stm32f4.s diff --git a/core/embed/reflash/startup_stm32u5.s b/core/embed/reflash/startup_stm32u5.s new file mode 100644 index 0000000000..3c10235961 --- /dev/null +++ b/core/embed/reflash/startup_stm32u5.s @@ -0,0 +1,67 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // setup environment for subsequent stage of code + 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, =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, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_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] + + // re-enable exceptions + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: + // "If it is not necessary to ensure that a pended interrupt is recognized immediately before + // subsequent operations, it is not necessary to insert a memory barrier instruction." + cpsie f + + // enter the application code + bl main + + b shutdown_privileged + + .end diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs index 0413e81c8e..18dd0670b3 100644 --- a/core/embed/rust/build.rs +++ b/core/embed/rust/build.rs @@ -447,7 +447,7 @@ fn generate_crypto_bindings() { fn is_firmware() -> bool { let target = env::var("TARGET").unwrap(); - target.starts_with("thumbv7") + target.starts_with("thumbv7") || target.starts_with("thumbv8") } #[cfg(feature = "test")] diff --git a/core/embed/trezorhal/board_capabilities.h b/core/embed/trezorhal/board_capabilities.h index b6e7b7befe..e7465960b0 100644 --- a/core/embed/trezorhal/board_capabilities.h +++ b/core/embed/trezorhal/board_capabilities.h @@ -35,7 +35,6 @@ Last tag must be terminator or all space used. #include -#define BOARD_CAPABILITIES_ADDR 0x0800BF00 #define BOARD_CAPABILITIES_SIZE 256 #define CAPABILITIES_HEADER "TRZC" diff --git a/core/embed/trezorhal/lowlevel.h b/core/embed/trezorhal/lowlevel.h index 49757aeac9..af207d6aec 100644 --- a/core/embed/trezorhal/lowlevel.h +++ b/core/embed/trezorhal/lowlevel.h @@ -27,6 +27,7 @@ void flash_lock_option_bytes(void); void flash_unlock_option_bytes(void); uint32_t flash_set_option_bytes(void); secbool flash_configure_option_bytes(void); +secbool flash_configure_sec_area_ob(void); void periph_init(void); secbool reset_flags_check(void); void reset_flags_reset(void); diff --git a/core/embed/trezorhal/mpu.h b/core/embed/trezorhal/mpu.h index 11db675596..d9c22de61d 100644 --- a/core/embed/trezorhal/mpu.h +++ b/core/embed/trezorhal/mpu.h @@ -21,6 +21,7 @@ #define __MPU_H__ void mpu_config_off(void); +void mpu_config_boardloader(void); void mpu_config_bootloader(void); void mpu_config_firmware(void); void mpu_config_prodtest(void); diff --git a/core/embed/trezorhal/secret.h b/core/embed/trezorhal/secret.h index 3366801473..2b226c3d67 100644 --- a/core/embed/trezorhal/secret.h +++ b/core/embed/trezorhal/secret.h @@ -7,6 +7,12 @@ #define SECRET_OPTIGA_KEY_OFFSET 16 #define SECRET_OPTIGA_KEY_LEN 32 +#define SECRET_MONOTONIC_COUNTER_OFFSET 48 +#define SECRET_MONOTONIC_COUNTER_LEN 1024 + +#define SECRET_BHK_OFFSET (1024 * 8) +#define SECRET_BHK_LEN 32 + secbool secret_bootloader_locked(void); void secret_write(uint8_t* data, uint32_t offset, uint32_t len); @@ -17,4 +23,22 @@ secbool secret_wiped(void); void secret_erase(void); +void secret_hide(void); + void secret_write_header(void); + +void secret_optiga_backup(void); + +void secret_optiga_hide(void); + +secbool secret_optiga_extract(uint8_t* dest); + +void secret_bhk_lock(void); + +secbool secret_bhk_locked(void); + +void secret_bhk_regenerate(void); + +void secret_bhk_provision(void); + +secbool secret_optiga_present(void); diff --git a/core/embed/trezorhal/secure_aes.h b/core/embed/trezorhal/secure_aes.h new file mode 100644 index 0000000000..78dedce73b --- /dev/null +++ b/core/embed/trezorhal/secure_aes.h @@ -0,0 +1,40 @@ +/* + * 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 . + */ + +#ifndef TREZOR_HAL_SECURE_AES_H +#define TREZOR_HAL_SECURE_AES_H + +#include +#include +#include + +// Initializes secure AES module +secbool secure_aes_init(void); + +// Encrypts a block of data using AES-256 EBB and (DHUK xor BHK) key +// Input and output must be aligned to 32 bits, size is in bytes +secbool secure_aes_encrypt(uint32_t* input, size_t size, uint32_t* output); + +// Decrypts a block of data using AES-256 ECB and (DHUK xor BHK) key +// Input and output must be aligned to 32 bits, size is in bytes +secbool secure_aes_decrypt(uint32_t* input, size_t size, uint32_t* output); + +void secure_aes_test(); + +#endif // TREZOR_HAL_SECURE_AES_H diff --git a/core/embed/trezorhal/stm32f4/board_capabilities.c b/core/embed/trezorhal/stm32f4/board_capabilities.c index abfd95d716..053987043f 100644 --- a/core/embed/trezorhal/stm32f4/board_capabilities.c +++ b/core/embed/trezorhal/stm32f4/board_capabilities.c @@ -20,6 +20,7 @@ #include "board_capabilities.h" #include #include "common.h" +#include "model.h" #define handle_fault(msg) \ (__fatal_error("Fault detected", msg, __FILE__, __LINE__, __func__)) diff --git a/core/embed/trezorhal/stm32f4/fault_handlers.c b/core/embed/trezorhal/stm32f4/fault_handlers.c new file mode 100644 index 0000000000..ae2f0bb092 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/fault_handlers.c @@ -0,0 +1,18 @@ +#include "common.h" + +void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(HF)"); } + +void MemManage_Handler_MM(void) { error_shutdown("INTERNAL ERROR", "(MM)"); } + +void MemManage_Handler_SO(void) { error_shutdown("INTERNAL ERROR", "(SO)"); } + +void BusFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(BF)"); } + +void UsageFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(UF)"); } + +void NMI_Handler(void) { + // Clock Security System triggered NMI + if ((RCC->CIR & RCC_CIR_CSSF) != 0) { + error_shutdown("INTERNAL ERROR", "(CS)"); + } +} diff --git a/core/embed/trezorhal/stm32f4/irq.h b/core/embed/trezorhal/stm32f4/irq.h index 1d06d4f958..319755f1c5 100644 --- a/core/embed/trezorhal/stm32f4/irq.h +++ b/core/embed/trezorhal/stm32f4/irq.h @@ -160,4 +160,7 @@ static inline void restore_irq_pri(uint32_t state) { #define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) #define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +// !@# TAMPER interrupt priority should be probably much higher +#define IRQ_PRI_TAMP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) + #endif // MICROPY_INCLUDED_STM32_IRQ_H diff --git a/core/embed/trezorhal/stm32f4/mpu.c b/core/embed/trezorhal/stm32f4/mpu.c index 98de82371e..1a7b79abce 100644 --- a/core/embed/trezorhal/stm32f4/mpu.c +++ b/core/embed/trezorhal/stm32f4/mpu.c @@ -33,6 +33,10 @@ void mpu_config_off(void) { HAL_MPU_Disable(); } +void mpu_config_boardloader(void) { + // nothing to be done +} + void mpu_config_bootloader(void) { // Disable MPU HAL_MPU_Disable(); diff --git a/core/embed/trezorhal/stm32f4/platform.h b/core/embed/trezorhal/stm32f4/platform.h index 89b7c2acc7..0c02ee1c8a 100644 --- a/core/embed/trezorhal/stm32f4/platform.h +++ b/core/embed/trezorhal/stm32f4/platform.h @@ -23,6 +23,8 @@ #include STM32_HAL_H #include +#define SENSITIVE + typedef enum { CLOCK_180_MHZ = 0, CLOCK_168_MHZ = 1, diff --git a/core/embed/trezorhal/stm32f4/secret.c b/core/embed/trezorhal/stm32f4/secret.c index 2232f889a7..33e8b66e5b 100644 --- a/core/embed/trezorhal/stm32f4/secret.c +++ b/core/embed/trezorhal/stm32f4/secret.c @@ -72,3 +72,7 @@ secbool secret_wiped(void) { void secret_erase(void) { ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); } + +secbool secret_optiga_extract(uint8_t* dest) { + return secret_read(dest, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); +} diff --git a/core/embed/trezorhal/stm32f4/supervise.c b/core/embed/trezorhal/stm32f4/supervise.c index 0a52028e6d..bb23f302d3 100644 --- a/core/embed/trezorhal/stm32f4/supervise.c +++ b/core/embed/trezorhal/stm32f4/supervise.c @@ -11,13 +11,13 @@ // Saves extra parameters for the bootloader static void _copy_boot_args(const void *args, size_t args_size) { // symbols imported from the linker script - extern uint8_t boot_args_start; + extern uint8_t g_boot_args; extern uint8_t boot_args_end; - uint8_t *p = &boot_args_start; + uint8_t *p = &g_boot_args; if (args != NULL && args_size > 0) { - size_t max_size = &boot_args_end - &boot_args_start; + size_t max_size = &boot_args_end - &g_boot_args; size_t copy_size = MIN(args_size, max_size); memcpy(p, args, copy_size); p += args_size; @@ -28,6 +28,16 @@ static void _copy_boot_args(const void *args, size_t args_size) { } } +#ifdef STM32U5 +extern uint32_t g_boot_flag; +__attribute__((noreturn)) static void _reboot_to_bootloader( + boot_command_t boot_command) { + g_boot_flag = boot_command; + __disable_irq(); + delete_secrets(); + NVIC_SystemReset(); +} +#else __attribute__((noreturn)) static void _reboot_to_bootloader( boot_command_t boot_command) { mpu_config_bootloader(); @@ -35,6 +45,7 @@ __attribute__((noreturn)) static void _reboot_to_bootloader( for (;;) ; } +#endif void svc_reboot_to_bootloader(boot_command_t boot_command, const void *args, size_t args_size) { diff --git a/core/embed/trezorhal/stm32f4/usb.c b/core/embed/trezorhal/stm32f4/usb.c index 0feaac1c1d..7a6ab42c96 100644 --- a/core/embed/trezorhal/stm32f4/usb.c +++ b/core/embed/trezorhal/stm32f4/usb.c @@ -32,6 +32,8 @@ #define USB_PHY_ID USB_PHY_FS_ID #elif defined(USE_USB_HS) && defined(USE_USB_HS_IN_FS) #define USB_PHY_ID USB_PHY_HS_ID +#elif defined(USE_USB_HS) && !defined(USE_USB_HS_IN_FS) +#define USB_PHY_ID USB_PHY_HS_ID #else #error Unable to determine proper USB_PHY_ID to use #endif diff --git a/core/embed/trezorhal/stm32f4/usbd_conf.c b/core/embed/trezorhal/stm32f4/usbd_conf.c index c9b45e3df0..589fbe04bd 100644 --- a/core/embed/trezorhal/stm32f4/usbd_conf.c +++ b/core/embed/trezorhal/stm32f4/usbd_conf.c @@ -83,6 +83,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { GPIO_InitTypeDef GPIO_InitStruct; +#ifdef USB_OTG_FS if(hpcd->Instance == USB_OTG_FS) { /* Configure USB FS GPIOs */ @@ -96,7 +97,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - /* Configure VBUS Pin */ + /* Configure VBUS Pin */ #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) // USB VBUS detect pin is always A9 GPIO_InitStruct.Pin = GPIO_PIN_9; @@ -124,9 +125,9 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USBFS Interrupt */ svc_enableIRQ(OTG_FS_IRQn); } +#endif #if defined(USE_USB_HS) - else if(hpcd->Instance == USB_OTG_HS) - { + if (hpcd->Instance == USB_OTG_HS) { #if defined(USE_USB_HS_IN_FS) /* Configure USB FS GPIOs */ @@ -168,7 +169,53 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USB HS Clocks */ __USB_OTG_HS_CLK_ENABLE(); -#else // !USE_USB_HS_IN_FS +#elif defined USE_USB_HS_INTERNAL_PHY && defined STM32U5 + + /* Configure DM and DP PINs */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + + GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12); + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_USB_HS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + + __HAL_RCC_SYSCFG_CLK_ENABLE(); + + + /** Initializes the peripherals clock + */ + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USBPHY; + PeriphClkInit.UsbPhyClockSelection = RCC_USBPHYCLKSOURCE_HSE; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); + + /** Set the OTG PHY reference clock selection + */ + HAL_SYSCFG_SetOTGPHYReferenceClockSelection(SYSCFG_OTG_HS_PHY_CLK_SELECT_1); + + /* Peripheral clock enable */ + __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); + __HAL_RCC_USBPHYC_CLK_ENABLE(); + + /* Enable VDDUSB */ + __HAL_RCC_PWR_CLK_ENABLE(); + HAL_PWREx_EnableVddUSB(); + + /*configure VOSR register of USB*/ + HAL_PWREx_EnableUSBHSTranceiverSupply(); + __HAL_RCC_PWR_CLK_DISABLE(); + + + /*Configuring the SYSCFG registers OTG_HS PHY*/ + /*OTG_HS PHY enable*/ + HAL_SYSCFG_EnableOTGPHY(SYSCFG_OTG_HS_PHY_ENABLE); + + + +#else // !USE_USB_HS_IN_FS && !USE_USB_HS_INTERNAL_PHY /* Configure USB HS GPIOs */ __HAL_RCC_GPIOA_CLK_ENABLE(); @@ -242,20 +289,22 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) */ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) { +#ifdef USB_OTG_FS if(hpcd->Instance == USB_OTG_FS) { /* Disable USB FS Clocks */ __HAL_RCC_USB_OTG_FS_CLK_DISABLE(); __HAL_RCC_SYSCFG_CLK_DISABLE(); } - #if defined(USE_USB_HS) - else if(hpcd->Instance == USB_OTG_HS) +#endif +#if defined(USE_USB_HS) + if(hpcd->Instance == USB_OTG_HS) { /* Disable USB FS Clocks */ __HAL_RCC_USB_OTG_HS_CLK_DISABLE(); __HAL_RCC_SYSCFG_CLK_DISABLE(); } - #endif +#endif } /******************************************************************************* @@ -440,6 +489,44 @@ USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev) } } #endif +#if defined(USE_USB_HS) && !defined(USE_USB_HS_IN_FS) && defined STM32U5 + // Trezor T uses the OTG_HS peripheral + if (pdev->id == USB_PHY_HS_ID) { + /* Set LL Driver parameters */ + pcd_hs_handle.Instance = USB_OTG_HS; + pcd_hs_handle.Init.dev_endpoints = 6; + pcd_hs_handle.Init.use_dedicated_ep1 = 0; + pcd_hs_handle.Init.ep0_mps = 0x40; + pcd_hs_handle.Init.dma_enable = 0; + pcd_hs_handle.Init.low_power_enable = 0; + pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; + pcd_hs_handle.Init.Sof_enable = 1; + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; + // Trezor T hardware has PB13 connected to HS_VBUS + // but we leave vbus sensing disabled because + // we don't use it for anything. the device is a bus powered peripheral. + pcd_hs_handle.Init.vbus_sensing_enable = 0; + /* Link The driver to the stack */ + pcd_hs_handle.pData = pdev; + pdev->pData = &pcd_hs_handle; + /* Initialize LL Driver */ + HAL_PCD_Init(&pcd_hs_handle); + // the OTG_HS peripheral has a dedicated 4KiB data RAM from which we + // allocate an area for each transmit FIFO and the single shared receive FIFO. + // the configuration is in terms of 32-bit words, so we have 1024 32-bit words + // in this dedicated 4KiB data RAM to use. see section 35.10.1 and 34.11 in RM0090. + // the reference to section 34.11 is for the OTG_FS device, but the FIFO architecture + // diagram seems to apply similarly to the FIFO in the OTG_HS that we are using. + // USB packets that we deal with are 64 bytes in size which equates to 16 32-bit words. + // we size the transmit FIFO's equally and give the rest of the space to the receive FIFO. + const uint16_t transmit_fifo_size = 144; // 144 = 16 * 9 meaning that we give 9 packets of space for each transmit fifo + const uint16_t receive_fifo_zie = 160; // 160 = 1024 - 6 * 144 section 35.10.1 details what some of this is used for besides storing packets + HAL_PCDEx_SetRxFiFo(&pcd_hs_handle, receive_fifo_zie); + for (uint16_t i = 0; i < 6; i++) { + HAL_PCDEx_SetTxFiFo(&pcd_hs_handle, i, transmit_fifo_size); + } + } +#endif #if defined(USE_USB_HS_IN_FS) // Trezor T uses the OTG_HS peripheral if (pdev->id == USB_PHY_HS_ID) { @@ -698,6 +785,7 @@ void OTG_HS_IRQHandler(void) { } #endif +#ifndef STM32U5 /** * @brief This function handles USB OTG Common FS/HS Wakeup functions. * @param *pcd_handle for FS or HS @@ -763,5 +851,6 @@ void OTG_HS_WKUP_IRQHandler(void) { IRQ_EXIT(OTG_HS_WKUP_IRQn); } #endif +#endif /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/core/embed/trezorhal/stm32f4/util.s b/core/embed/trezorhal/stm32f4/util.s index 5052206211..30349678d9 100644 --- a/core/embed/trezorhal/stm32f4/util.s +++ b/core/embed/trezorhal/stm32f4/util.s @@ -167,4 +167,16 @@ shutdown_privileged: ldr r0, =0 b . // loop forever + .global MemManage_Handler + .type MemManage_Handler, STT_FUNC +MemManage_Handler: + ldr r2, =_sstack + mrs r1, msp + ldr r0, =_estack + msr msp, r0 + cmp r1, r2 + IT lt + bllt MemManage_Handler_SO + bl MemManage_Handler_MM + .end diff --git a/core/embed/trezorhal/stm32u5/board_capabilities.c b/core/embed/trezorhal/stm32u5/board_capabilities.c new file mode 120000 index 0000000000..da6d3b1a3d --- /dev/null +++ b/core/embed/trezorhal/stm32u5/board_capabilities.c @@ -0,0 +1 @@ +../stm32f4/board_capabilities.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/common.c b/core/embed/trezorhal/stm32u5/common.c new file mode 100644 index 0000000000..c5bab03afd --- /dev/null +++ b/core/embed/trezorhal/stm32u5/common.c @@ -0,0 +1,205 @@ +/* + * 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 . + */ + +#include STM32_HAL_H + +#include + +#include "common.h" +#include "display.h" +#include "secret.h" +#include "terminal.h" +#ifdef FANCY_FATAL_ERROR +#include "rust_ui.h" +#endif +#include "flash.h" +#include "model.h" +#include "platform.h" +#include "rand.h" +#include "supervise.h" + +#include "mini_printf.h" +#include "stm32u5xx_ll_utils.h" + +#ifdef RGB16 +#define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00) +#else +#define COLOR_FATAL_ERROR COLOR_BLACK +#endif + +uint32_t systick_val_copy = 0; + +// from util.s +extern void shutdown_privileged(void); + +void __attribute__((noreturn)) trezor_shutdown(void) { + __HAL_RCC_SAES_CLK_DISABLE(); + // Erase all secrets + TAMP->CR2 |= TAMP_CR2_BKERASE; + +#ifdef USE_SVC_SHUTDOWN + svc_shutdown(); +#else + // It won't work properly unless called from the privileged mode + shutdown_privileged(); +#endif + + for (;;) + ; +} + +void __attribute__((noreturn)) +error_uni(const char *label, const char *msg, const char *footer) { + display_orientation(0); + +#ifdef FANCY_FATAL_ERROR + + screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); + display_refresh(); +#else + term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); + if (label) { + term_printf("%s\n", label); + } + if (msg) { + term_printf("%s\n", msg); + } + if (footer) { + term_printf("\n%s\n", footer); + } +#endif + display_backlight(255); + display_refresh(); + trezor_shutdown(); +} + +void __attribute__((noreturn)) +__fatal_error(const char *expr, const char *msg, const char *file, int line, + const char *func) { + display_orientation(0); + display_backlight(255); + +#ifdef FANCY_FATAL_ERROR + char buf[256] = {0}; + mini_snprintf(buf, sizeof(buf), "%s: %d", file, line); + screen_fatal_error_rust("INTERNAL ERROR", msg != NULL ? msg : buf, + "PLEASE VISIT\nTREZOR.IO/RSOD"); + display_refresh(); +#else + term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); + term_printf("\nINTERNAL ERROR:\n"); + if (expr) { + term_printf("expr: %s\n", expr); + } + if (msg) { + term_printf("msg : %s\n", msg); + } + if (file) { + term_printf("file: %s:%d\n", file, line); + } + if (func) { + term_printf("func: %s\n", func); + } +#ifdef SCM_REVISION + const uint8_t *rev = (const uint8_t *)SCM_REVISION; + term_printf("rev : %02x%02x%02x%02x%02x\n", rev[0], rev[1], rev[2], rev[3], + rev[4]); +#endif + term_printf("\nPlease contact Trezor support.\n"); +#endif + trezor_shutdown(); +} + +void __attribute__((noreturn)) +error_shutdown(const char *label, const char *msg) { + display_orientation(0); + +#ifdef FANCY_FATAL_ERROR + + screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); + display_refresh(); +#else + term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); + if (label) { + term_printf("%s\n", label); + } + if (msg) { + term_printf("%s\n", msg); + } + term_printf("\nPLEASE VISIT TREZOR.IO/RSOD\n"); +#endif + display_backlight(255); + trezor_shutdown(); +} + +#ifndef NDEBUG +void __assert_func(const char *file, int line, const char *func, + const char *expr) { + __fatal_error(expr, "assert failed", file, line, func); +} +#endif + +void hal_delay(uint32_t ms) { HAL_Delay(ms); } +uint32_t hal_ticks_ms() { return HAL_GetTick(); } + +uint32_t __stack_chk_guard = 0; + +void __attribute__((noreturn)) __stack_chk_fail(void) { + error_shutdown("INTERNAL ERROR", "(SS)"); +} + +uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; + +void collect_hw_entropy(void) { + // collect entropy from UUID + uint32_t w = LL_GetUID_Word0(); + memcpy(HW_ENTROPY_DATA, &w, 4); + w = LL_GetUID_Word1(); + memcpy(HW_ENTROPY_DATA + 4, &w, 4); + w = LL_GetUID_Word2(); + memcpy(HW_ENTROPY_DATA + 8, &w, 4); + + // set entropy in the OTP randomness block + if (secfalse == flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) { + uint8_t entropy[FLASH_OTP_BLOCK_SIZE]; + random_buffer(entropy, FLASH_OTP_BLOCK_SIZE); + ensure(flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy, + FLASH_OTP_BLOCK_SIZE), + NULL); + // ensure(flash_otp_lock(FLASH_OTP_BLOCK_RANDOMNESS), NULL); + } + // collect entropy from OTP randomness block + ensure(flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, HW_ENTROPY_DATA + 12, + FLASH_OTP_BLOCK_SIZE), + NULL); +} + +// this function resets settings changed in one layer (bootloader/firmware), +// which might be incompatible with the other layers older versions, +// where this setting might be unknown +void ensure_compatible_settings(void) {} + +void show_wipe_code_screen(void) { + error_uni("WIPE CODE ENTERED", "All data has been erased from the device", + "PLEASE RECONNECT\nTHE DEVICE"); +} +void show_pin_too_many_screen(void) { + error_uni("TOO MANY PIN ATTEMPTS", "All data has been erased from the device", + "PLEASE RECONNECT\nTHE DEVICE"); +} diff --git a/core/embed/trezorhal/stm32u5/dma2d.c b/core/embed/trezorhal/stm32u5/dma2d.c new file mode 120000 index 0000000000..449adb7584 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/dma2d.c @@ -0,0 +1 @@ +../stm32f4/dma2d.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/fault_handlers.c b/core/embed/trezorhal/stm32u5/fault_handlers.c new file mode 100644 index 0000000000..94f9609da8 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/fault_handlers.c @@ -0,0 +1,22 @@ +#include "common.h" + +void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(HF)"); } + +void MemManage_Handler_MM(void) { error_shutdown("INTERNAL ERROR", "(MM)"); } + +void MemManage_Handler_SO(void) { error_shutdown("INTERNAL ERROR", "(SO)"); } + +void BusFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(BF)"); } + +void UsageFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(UF)"); } + +void SecureFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(SF)"); } + +void GTZC_IRQHandler(void) { error_shutdown("INTERNAL ERROR", "(IA)"); } + +void NMI_Handler(void) { + // Clock Security System triggered NMI + if ((RCC->CIFR & RCC_CIFR_CSSF) != 0) { + error_shutdown("INTERNAL ERROR", "(CS)"); + } +} diff --git a/core/embed/trezorhal/stm32u5/flash.c b/core/embed/trezorhal/stm32u5/flash.c new file mode 100644 index 0000000000..7c8dc0ec90 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/flash.c @@ -0,0 +1,567 @@ +/* + * 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 . + */ + +#include STM32_HAL_H + +#include + +#include "common.h" +#include "flash.h" +#include "model.h" + +#define FLASH_SEC_START_ADDRESS 0x0C000000 +#define FLASH_START_ADDRESS 0x08000000 + +#define FLASH_SECTOR_COUNT (256 * 2) + +#define FLASH_STATUS_ALL_FLAGS \ + (FLASH_NSSR_PGSERR | FLASH_NSSR_PGAERR | FLASH_NSSR_WRPERR | FLASH_NSSR_EOP) + +uint32_t flash_wait_and_clear_status_flags(void) { + while (FLASH->NSSR & FLASH_NSSR_BSY) + ; // wait for all previous flash operations to complete + + uint32_t result = + FLASH->NSSR & FLASH_STATUS_ALL_FLAGS; // get the current status flags + FLASH->NSSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags + +#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + while (FLASH->SECSR & FLASH_SECSR_BSY) + ; // wait for all previous flash operations to complete + result |= + FLASH->SECSR & FLASH_STATUS_ALL_FLAGS; // get the current status flags + FLASH->SECSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags +#endif + return result; +} + +secbool flash_unlock_write(void) { + HAL_FLASH_Unlock(); + FLASH->NSSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags +#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + FLASH->SECSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags +#endif + return sectrue; +} + +secbool flash_lock_write(void) { + HAL_FLASH_Lock(); + return sectrue; +} + +const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size, + bool secure_area) { + if (sector >= FLASH_SECTOR_COUNT) { + return NULL; + } + uint32_t base_addr = FLASH_START_ADDRESS; + + if (secure_area) { + base_addr = FLASH_SEC_START_ADDRESS; + } + + const uint32_t addr = base_addr + (FLASH_PAGE_SIZE * sector) + offset; + const uint32_t next = base_addr + (FLASH_PAGE_SIZE * (sector + 1)); + if (addr + size > next) { + return NULL; + } + return (const void *)addr; +} + +uint32_t flash_sector_size(uint16_t sector) { + if (sector >= FLASH_SECTOR_COUNT) { + return 0; + } + return FLASH_PAGE_SIZE; +} + +uint32_t flash_subarea_get_size(const flash_subarea_t *sub) { + return FLASH_PAGE_SIZE * sub->num_sectors; +} + +uint32_t flash_area_get_size(const flash_area_t *area) { + uint32_t size = 0; + for (int i = 0; i < area->num_subareas; i++) { + size += flash_subarea_get_size(&area->subarea[i]); + } + return size; +} + +uint16_t flash_total_sectors(const flash_area_t *area) { + uint16_t total = 0; + for (int i = 0; i < area->num_subareas; i++) { + total += area->subarea[i].num_sectors; + } + return total; +} + +const void *flash_area_get_address(const flash_area_t *area, uint32_t offset, + uint32_t size) { + uint32_t tmp_offset = offset; + + for (int i = 0; i < area->num_subareas; i++) { + uint16_t sector = area->subarea[i].first_sector; + + if (tmp_offset >= flash_subarea_get_size(area->subarea)) { + tmp_offset -= flash_subarea_get_size(area->subarea); + continue; + } + + uint32_t base_addr = FLASH_START_ADDRESS; + + if (area->secure_area) { + base_addr = FLASH_SEC_START_ADDRESS; + } + + const uint32_t addr = base_addr + (FLASH_PAGE_SIZE * sector) + tmp_offset; + const uint32_t area_end = + base_addr + (FLASH_PAGE_SIZE * (area->subarea[i].first_sector + + area->subarea[i].num_sectors)); + if (addr + size > area_end) { + return NULL; + } + return (const void *)addr; + } + return NULL; +} + +int32_t flash_get_sector_num(const flash_area_t *area, + uint32_t sector_inner_num) { + uint16_t sector = 0; + uint16_t remaining = sector_inner_num; + for (int i = 0; i < area->num_subareas; i++) { + if (remaining < area->subarea[i].num_sectors) { + sector = area->subarea[i].first_sector + remaining; + return sector; + } else { + remaining -= area->subarea[i].num_sectors; + } + } + + return -1; +} + +secbool flash_area_erase(const flash_area_t *area, + void (*progress)(int pos, int len)) { + ensure(flash_unlock_write(), NULL); + FLASH_EraseInitTypeDef EraseInitStruct; + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.NbPages = 1; + + int total_pages = 0; + int done_pages = 0; + for (int i = 0; i < area->num_subareas; i++) { + total_pages += area->subarea[i].num_sectors; + } + + if (progress) { + progress(0, total_pages); + } + + for (int s = 0; s < area->num_subareas; s++) { + for (int i = 0; i < area->subarea[s].num_sectors; i++) { + int page = area->subarea[s].first_sector + i; + uint32_t sec_start = 0; + uint32_t sec_end = 0; + uint32_t page_idx = 0; + bool secure = area->secure_area; + if (page >= 256) { + EraseInitStruct.Banks = FLASH_BANK_2; + page_idx = page - 256; + sec_start = (FLASH->SECWM2R1 & FLASH_SECWM1R1_SECWM1_PSTRT) >> + FLASH_SECWM1R1_SECWM1_PSTRT_Pos; + sec_end = (FLASH->SECWM2R1 & FLASH_SECWM1R1_SECWM1_PEND) >> + FLASH_SECWM1R1_SECWM1_PEND_Pos; + } else { + EraseInitStruct.Banks = FLASH_BANK_1; + page_idx = page; + sec_start = (FLASH->SECWM1R1 & FLASH_SECWM1R1_SECWM1_PSTRT) >> + FLASH_SECWM1R1_SECWM1_PSTRT_Pos; + sec_end = (FLASH->SECWM1R1 & FLASH_SECWM1R1_SECWM1_PEND) >> + FLASH_SECWM1R1_SECWM1_PEND_Pos; + } + + if (page_idx < sec_start || page_idx > sec_end) { + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES_NS; + secure = false; + } else { + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + } + + EraseInitStruct.Page = page_idx; + uint32_t SectorError; + if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { + ensure(flash_lock_write(), NULL); + return secfalse; + } + // check whether the sector was really deleted (contains only 0xFF) + const uint32_t addr_start = + (uint32_t)flash_get_address(page, 0, 0, secure); + const uint32_t addr_end = + (uint32_t)flash_get_address(page + 1, 0, 0, secure); + + for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { + if (*((const uint32_t *)addr) != 0xFFFFFFFF) { + ensure(flash_lock_write(), NULL); + return secfalse; + } + } + done_pages++; + if (progress && done_pages % 16 == 0) { + progress(done_pages, total_pages); + } + } + } + ensure(flash_lock_write(), NULL); + return sectrue; +} + +secbool flash_area_erase_bulk(const flash_area_t *areas, int count, + void (*progress)(int pos, int len)) { + ensure(flash_unlock_write(), NULL); + FLASH_EraseInitTypeDef EraseInitStruct; + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.NbPages = 1; + + int total_pages = 0; + int done_pages = 0; + for (int c = 0; c < count; c++) { + for (int i = 0; i < areas[c].num_subareas; i++) { + total_pages += areas[c].subarea[i].num_sectors; + } + } + + if (progress) { + progress(0, total_pages); + } + + for (int c = 0; c < count; c++) { + for (int s = 0; s < areas[c].num_subareas; s++) { + for (int i = 0; i < areas[c].subarea[s].num_sectors; i++) { + int page = areas[c].subarea[s].first_sector + i; + if (page >= 256) { + EraseInitStruct.Banks = FLASH_BANK_2; + } else { + EraseInitStruct.Banks = FLASH_BANK_1; + } + EraseInitStruct.Page = page; + uint32_t SectorError; + if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { + ensure(flash_lock_write(), NULL); + return secfalse; + } + // check whether the sector was really deleted (contains only 0xFF) + const uint32_t addr_start = + (uint32_t)flash_get_address(page, 0, 0, areas[c].secure_area); + const uint32_t addr_end = + (uint32_t)flash_get_address(page + 1, 0, 0, areas[c].secure_area); + + for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { + if (*((const uint32_t *)addr) != 0xFFFFFFFF) { + ensure(flash_lock_write(), NULL); + return secfalse; + } + } + done_pages++; + if (progress) { + progress(done_pages, total_pages); + } + } + } + } + ensure(flash_lock_write(), NULL); + return sectrue; +} + +secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset, + uint32_t *bytes_erased) { + ensure(flash_unlock_write(), NULL); + FLASH_EraseInitTypeDef EraseInitStruct; + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.NbPages = 1; + + *bytes_erased = 0; + int32_t page = flash_get_sector_num(area, offset / FLASH_PAGE_SIZE); + + if (page >= 0 && page < FLASH_SECTOR_COUNT) { + uint32_t sec_start = 0; + uint32_t sec_end = 0; + uint32_t page_idx = 0; + bool secure = area->secure_area; + if (page >= 256) { + EraseInitStruct.Banks = FLASH_BANK_2; + page_idx = page - 256; + sec_start = (FLASH->SECWM2R1 & FLASH_SECWM1R1_SECWM1_PSTRT) >> + FLASH_SECWM1R1_SECWM1_PSTRT_Pos; + sec_end = (FLASH->SECWM2R1 & FLASH_SECWM1R1_SECWM1_PEND) >> + FLASH_SECWM1R1_SECWM1_PEND_Pos; + } else { + EraseInitStruct.Banks = FLASH_BANK_1; + page_idx = page; + sec_start = (FLASH->SECWM1R1 & FLASH_SECWM1R1_SECWM1_PSTRT) >> + FLASH_SECWM1R1_SECWM1_PSTRT_Pos; + sec_end = (FLASH->SECWM1R1 & FLASH_SECWM1R1_SECWM1_PEND) >> + FLASH_SECWM1R1_SECWM1_PEND_Pos; + } + + if (page_idx < sec_start || page_idx > sec_end) { + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES_NS; + secure = false; + } else { + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + } + + EraseInitStruct.Page = page_idx; + uint32_t SectorError; + if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { + ensure(flash_lock_write(), NULL); + return secfalse; + } + // check whether the sector was really deleted (contains only 0xFF) + const uint32_t addr_start = (uint32_t)flash_get_address(page, 0, 0, secure); + const uint32_t addr_end = + (uint32_t)flash_get_address(page + 1, 0, 0, secure); + + for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { + if (*((const uint32_t *)addr) != 0xFFFFFFFF) { + ensure(flash_lock_write(), NULL); + return secfalse; + } + } + ensure(flash_lock_write(), NULL); + *bytes_erased = FLASH_PAGE_SIZE; + return sectrue; + } + ensure(flash_lock_write(), NULL); + return sectrue; +} + +secbool flash_write_quadword(uint16_t sector, uint32_t offset, + const uint32_t *data, bool secure_area) { + uint32_t address = (uint32_t)flash_get_address( + sector, offset, 4 * sizeof(uint32_t), secure_area); + if (address == 0) { + return secfalse; + } + if (offset % (4 * sizeof(uint32_t))) { // we write only at 16-byte boundary + return secfalse; + } + + for (int i = 0; i < 4; i++) { + if (data[i] != (data[i] & *((const uint32_t *)address + i))) { + return secfalse; + } + } + + secbool all_match = sectrue; + for (int i = 0; i < 4; i++) { + if (data[i] != *((const uint32_t *)address + i)) { + all_match = secfalse; + break; + } + } + if (all_match == sectrue) { + return sectrue; + } + + if (HAL_OK != + HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, address, (uint32_t)data)) { + return secfalse; + } + + for (int i = 0; i < 4; i++) { + if (data[i] != *((const uint32_t *)address + i)) { + return secfalse; + } + } + return sectrue; +} + +secbool flash_write_burst(uint16_t sector, uint32_t offset, + const uint32_t *data, bool secure_area) { + uint32_t address = (uint32_t)flash_get_address( + sector, offset, 8 * 4 * sizeof(uint32_t), secure_area); + if (address == 0) { + return secfalse; + } + if (offset % + (8 * 4 * sizeof(uint32_t))) { // we write only at 16-byte boundary + return secfalse; + } + + for (int i = 0; i < 8 * 4; i++) { + if (data[i] != (data[i] & *((const uint32_t *)address + i))) { + return secfalse; + } + } + + secbool all_match = sectrue; + for (int i = 0; i < 8 * 4; i++) { + if (data[i] != *((const uint32_t *)address + i)) { + all_match = secfalse; + break; + } + } + if (all_match == sectrue) { + return sectrue; + } + + if (HAL_OK != + HAL_FLASH_Program(FLASH_TYPEPROGRAM_BURST, address, (uint32_t)data)) { + return secfalse; + } + + for (int i = 0; i < 8 * 4; i++) { + if (data[i] != *((const uint32_t *)address + i)) { + return secfalse; + } + } + return sectrue; +} + +secbool flash_area_write_quadword(const flash_area_t *area, uint32_t offset, + const uint32_t *data) { + uint32_t tmp_offset = offset; + for (int i = 0; i < area->num_subareas; i++) { + uint16_t sector = area->subarea[i].first_sector; + + uint32_t sub_size = flash_subarea_get_size(&area->subarea[i]); + if (tmp_offset >= sub_size) { + tmp_offset -= sub_size; + continue; + } + + // in correct subarea + for (int s = 0; s < area->subarea[i].num_sectors; s++) { + const uint32_t sector_size = flash_sector_size(sector); + if (tmp_offset >= sector_size) { + tmp_offset -= sector_size; + sector++; + + if (s == area->subarea[i].num_sectors - 1) { + return secfalse; + } + continue; + } + // in correct sector + return flash_write_quadword(sector, tmp_offset, data, area->secure_area); + } + } + return secfalse; +} + +secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset, + const uint32_t *data) { + uint32_t tmp_offset = offset; + for (int i = 0; i < area->num_subareas; i++) { + uint16_t sector = area->subarea[i].first_sector; + + uint32_t sub_size = flash_subarea_get_size(&area->subarea[i]); + if (tmp_offset >= sub_size) { + tmp_offset -= sub_size; + continue; + } + + // in correct subarea + for (int s = 0; s < area->subarea[i].num_sectors; s++) { + const uint32_t sector_size = flash_sector_size(sector); + if (tmp_offset >= sector_size) { + tmp_offset -= sector_size; + sector++; + + if (s == area->subarea[i].num_sectors - 1) { + return secfalse; + } + continue; + } + // in correct sector + return flash_write_burst(sector, tmp_offset, data, area->secure_area); + } + } + return secfalse; +} + +secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, + uint8_t datalen) { + if (block >= FLASH_OTP_NUM_BLOCKS || + offset + datalen > FLASH_OTP_BLOCK_SIZE) { + return secfalse; + } + for (uint8_t i = 0; i < datalen; i++) { + data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + + offset + i); + } + return sectrue; +} + +secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, + uint8_t datalen) { + if (datalen % 16 != 0) { + return secfalse; + } + if (block >= FLASH_OTP_NUM_BLOCKS || + offset + datalen > FLASH_OTP_BLOCK_SIZE) { + return secfalse; + } + ensure(flash_unlock_write(), NULL); + for (uint8_t i = 0; i < datalen; i++) { + uint32_t address = + FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i; + ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, + address, (uint32_t)data)), + NULL); + } + ensure(flash_lock_write(), NULL); + return sectrue; +} + +secbool flash_otp_lock(uint8_t block) { + // check that all quadwords in the block have been written to + volatile uint8_t *addr = + (__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE); + + secbool qw_locked = secfalse; + for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) { + if (addr[i] != 0xFF) { + qw_locked = sectrue; + } + if (i % 16 == 15 && qw_locked == secfalse) { + return secfalse; + } + } + return sectrue; +} + +secbool flash_otp_is_locked(uint8_t block) { + // considering block locked if any quadword in the block is non-0xFF + volatile uint8_t *addr = + (__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE); + + for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) { + if (addr[i] != 0xFF) { + return sectrue; + } + } + return secfalse; +} + +secbool flash_write_block(uint16_t sector, uint32_t offset, + const flash_block_t block) { + return flash_write_quadword(sector, offset, block); +} diff --git a/core/embed/trezorhal/stm32u5/i2c.c b/core/embed/trezorhal/stm32u5/i2c.c new file mode 100644 index 0000000000..cf2ecfa04a --- /dev/null +++ b/core/embed/trezorhal/stm32u5/i2c.c @@ -0,0 +1,441 @@ + + +#include STM32_HAL_H +#include TREZOR_BOARD +#include "i2c.h" +#include "common.h" + +static I2C_HandleTypeDef i2c_handle[I2C_COUNT]; + +typedef struct { + I2C_TypeDef *Instance; + GPIO_TypeDef *SclPort; + GPIO_TypeDef *SdaPort; + uint16_t SclPin; + uint16_t SdaPin; + uint8_t PinAF; + volatile uint32_t *ResetReg; + uint32_t ResetBit; +} i2c_instance_t; + +i2c_instance_t i2c_defs[I2C_COUNT] = { + { + .Instance = I2C_INSTANCE_1, + .SclPort = I2C_INSTANCE_1_SCL_PORT, + .SdaPort = I2C_INSTANCE_1_SDA_PORT, + .SclPin = I2C_INSTANCE_1_SCL_PIN, + .SdaPin = I2C_INSTANCE_1_SDA_PIN, + .PinAF = I2C_INSTANCE_1_PIN_AF, + .ResetReg = I2C_INSTANCE_1_RESET_REG, + .ResetBit = I2C_INSTANCE_1_RESET_BIT, + }, +#ifdef I2C_INSTANCE_2 + { + .Instance = I2C_INSTANCE_2, + .SclPort = I2C_INSTANCE_2_SCL_PORT, + .SdaPort = I2C_INSTANCE_2_SDA_PORT, + .SclPin = I2C_INSTANCE_2_SCL_PIN, + .SdaPin = I2C_INSTANCE_2_SDA_PIN, + .PinAF = I2C_INSTANCE_2_PIN_AF, + .ResetReg = I2C_INSTANCE_2_RESET_REG, + .ResetBit = I2C_INSTANCE_2_RESET_BIT, + }, +#endif + +}; + +#ifndef I2C_VALID_TIMING_NBR +#define I2C_VALID_TIMING_NBR 128U +#endif /* I2C_VALID_TIMING_NBR */ + +#define I2C_SPEED_FREQ_STANDARD 0U /* 100 kHz */ +#define I2C_SPEED_FREQ_FAST 1U /* 400 kHz */ +#define I2C_SPEED_FREQ_FAST_PLUS 2U /* 1 MHz */ +#define I2C_ANALOG_FILTER_DELAY_MIN 50U /* ns */ +#define I2C_ANALOG_FILTER_DELAY_MAX 260U /* ns */ +#define I2C_USE_ANALOG_FILTER 1U +#define I2C_DIGITAL_FILTER_COEF 0U +#define I2C_PRESC_MAX 16U +#define I2C_SCLDEL_MAX 16U +#define I2C_SDADEL_MAX 16U +#define I2C_SCLH_MAX 256U +#define I2C_SCLL_MAX 256U +#define SEC2NSEC 1000000000UL +/** + * @} + */ + +/** @defgroup STM32U5x9J_DISCOVERY_BUS_Private_Types BUS Private Types + * @{ + */ +typedef struct { + uint32_t freq; /* Frequency in Hz */ + uint32_t freq_min; /* Minimum frequency in Hz */ + uint32_t freq_max; /* Maximum frequency in Hz */ + uint32_t hddat_min; /* Minimum data hold time in ns */ + uint32_t vddat_max; /* Maximum data valid time in ns */ + uint32_t sudat_min; /* Minimum data setup time in ns */ + uint32_t lscl_min; /* Minimum low period of the SCL clock in ns */ + uint32_t hscl_min; /* Minimum high period of SCL clock in ns */ + uint32_t trise; /* Rise time in ns */ + uint32_t tfall; /* Fall time in ns */ + uint32_t dnf; /* Digital noise filter coefficient */ +} I2C_Charac_t; + +typedef struct { + uint32_t presc; /* Timing prescaler */ + uint32_t tscldel; /* SCL delay */ + uint32_t tsdadel; /* SDA delay */ + uint32_t sclh; /* SCL high period */ + uint32_t scll; /* SCL low period */ +} I2C_Timings_t; + +static I2C_Timings_t I2c_valid_timing[I2C_VALID_TIMING_NBR]; +static uint32_t I2c_valid_timing_nbr = 0; + +static const I2C_Charac_t I2C_Charac[] = { + [I2C_SPEED_FREQ_STANDARD] = + { + .freq = 100000, + .freq_min = 80000, + .freq_max = 120000, + .hddat_min = 0, + .vddat_max = 3450, + .sudat_min = 250, + .lscl_min = 4700, + .hscl_min = 4000, + .trise = 640, + .tfall = 20, + .dnf = I2C_DIGITAL_FILTER_COEF, + }, + [I2C_SPEED_FREQ_FAST] = + { + .freq = 400000, + .freq_min = 320000, + .freq_max = 480000, + .hddat_min = 0, + .vddat_max = 900, + .sudat_min = 100, + .lscl_min = 1300, + .hscl_min = 600, + .trise = 250, + .tfall = 100, + .dnf = I2C_DIGITAL_FILTER_COEF, + }, + [I2C_SPEED_FREQ_FAST_PLUS] = + { + .freq = 1000000, + .freq_min = 800000, + .freq_max = 1200000, + .hddat_min = 0, + .vddat_max = 450, + .sudat_min = 50, + .lscl_min = 500, + .hscl_min = 260, + .trise = 60, + .tfall = 100, + .dnf = I2C_DIGITAL_FILTER_COEF, + }, +}; + +/** + * @brief Compute PRESC, SCLDEL and SDADEL. + * @param clock_src_freq I2C source clock in HZ. + * @param I2C_speed I2C frequency (index). + * @retval None. + */ +static void I2C_Compute_PRESC_SCLDEL_SDADEL(uint32_t clock_src_freq, + uint32_t I2C_speed) { + uint32_t prev_presc = I2C_PRESC_MAX; + uint32_t ti2cclk; + int32_t tsdadel_min; + int32_t tsdadel_max; + int32_t tscldel_min; + uint32_t presc; + uint32_t scldel; + uint32_t sdadel; + uint32_t tafdel_min; + uint32_t tafdel_max; + ti2cclk = (SEC2NSEC + (clock_src_freq / 2U)) / clock_src_freq; + + tafdel_min = I2C_ANALOG_FILTER_DELAY_MIN; + tafdel_max = I2C_ANALOG_FILTER_DELAY_MAX; + + /* tDNF = DNF x tI2CCLK + tPRESC = (PRESC+1) x tI2CCLK + SDADEL >= {tf +tHD;DAT(min) - tAF(min) - tDNF - [3 x tI2CCLK]} / {tPRESC} + SDADEL <= {tVD;DAT(max) - tr - tAF(max) - tDNF- [4 x tI2CCLK]} / {tPRESC} + */ + + tsdadel_min = + (int32_t)I2C_Charac[I2C_speed].tfall + + (int32_t)I2C_Charac[I2C_speed].hddat_min - (int32_t)tafdel_min - + (int32_t)(((int32_t)I2C_Charac[I2C_speed].dnf + 3) * (int32_t)ti2cclk); + + tsdadel_max = + (int32_t)I2C_Charac[I2C_speed].vddat_max - + (int32_t)I2C_Charac[I2C_speed].trise - (int32_t)tafdel_max - + (int32_t)(((int32_t)I2C_Charac[I2C_speed].dnf + 4) * (int32_t)ti2cclk); + + /* {[tr+ tSU;DAT(min)] / [tPRESC]} - 1 <= SCLDEL */ + tscldel_min = (int32_t)I2C_Charac[I2C_speed].trise + + (int32_t)I2C_Charac[I2C_speed].sudat_min; + + if (tsdadel_min <= 0) { + tsdadel_min = 0; + } + + if (tsdadel_max <= 0) { + tsdadel_max = 0; + } + + for (presc = 0; presc < I2C_PRESC_MAX; presc++) { + for (scldel = 0; scldel < I2C_SCLDEL_MAX; scldel++) { + /* TSCLDEL = (SCLDEL+1) * (PRESC+1) * TI2CCLK */ + uint32_t tscldel = (scldel + 1U) * (presc + 1U) * ti2cclk; + + if (tscldel >= (uint32_t)tscldel_min) { + for (sdadel = 0; sdadel < I2C_SDADEL_MAX; sdadel++) { + /* TSDADEL = SDADEL * (PRESC+1) * TI2CCLK */ + uint32_t tsdadel = (sdadel * (presc + 1U)) * ti2cclk; + + if ((tsdadel >= (uint32_t)tsdadel_min) && + (tsdadel <= (uint32_t)tsdadel_max)) { + if (presc != prev_presc) { + I2c_valid_timing[I2c_valid_timing_nbr].presc = presc; + I2c_valid_timing[I2c_valid_timing_nbr].tscldel = scldel; + I2c_valid_timing[I2c_valid_timing_nbr].tsdadel = sdadel; + prev_presc = presc; + I2c_valid_timing_nbr++; + + if (I2c_valid_timing_nbr >= I2C_VALID_TIMING_NBR) { + return; + } + } + } + } + } + } + } +} + +/** + * @brief Calculate SCLL and SCLH and find best configuration. + * @param clock_src_freq I2C source clock in HZ. + * @param I2C_speed I2C frequency (index). + * @retval config index (0 to I2C_VALID_TIMING_NBR], 0xFFFFFFFF for no valid + * config. + */ +static uint32_t I2C_Compute_SCLL_SCLH(uint32_t clock_src_freq, + uint32_t I2C_speed) { + uint32_t ret = 0xFFFFFFFFU; + uint32_t ti2cclk; + uint32_t ti2cspeed; + uint32_t prev_error; + uint32_t dnf_delay; + uint32_t clk_min; + uint32_t clk_max; + uint32_t scll; + uint32_t sclh; + uint32_t tafdel_min; + + ti2cclk = (SEC2NSEC + (clock_src_freq / 2U)) / clock_src_freq; + ti2cspeed = (SEC2NSEC + (I2C_Charac[I2C_speed].freq / 2U)) / + I2C_Charac[I2C_speed].freq; + + tafdel_min = I2C_ANALOG_FILTER_DELAY_MIN; + + /* tDNF = DNF x tI2CCLK */ + dnf_delay = I2C_Charac[I2C_speed].dnf * ti2cclk; + + clk_max = SEC2NSEC / I2C_Charac[I2C_speed].freq_min; + clk_min = SEC2NSEC / I2C_Charac[I2C_speed].freq_max; + + prev_error = ti2cspeed; + + for (uint32_t count = 0; count < I2c_valid_timing_nbr; count++) { + /* tPRESC = (PRESC+1) x tI2CCLK*/ + uint32_t tpresc = (I2c_valid_timing[count].presc + 1U) * ti2cclk; + + for (scll = 0; scll < I2C_SCLL_MAX; scll++) { + /* tLOW(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLL+1) x tPRESC ] */ + uint32_t tscl_l = + tafdel_min + dnf_delay + (2U * ti2cclk) + ((scll + 1U) * tpresc); + + /* The I2CCLK period tI2CCLK must respect the following conditions: + tI2CCLK < (tLOW - tfilters) / 4 and tI2CCLK < tHIGH */ + if ((tscl_l > I2C_Charac[I2C_speed].lscl_min) && + (ti2cclk < ((tscl_l - tafdel_min - dnf_delay) / 4U))) { + for (sclh = 0; sclh < I2C_SCLH_MAX; sclh++) { + /* tHIGH(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLH+1) x tPRESC] + */ + uint32_t tscl_h = + tafdel_min + dnf_delay + (2U * ti2cclk) + ((sclh + 1U) * tpresc); + + /* tSCL = tf + tLOW + tr + tHIGH */ + uint32_t tscl = tscl_l + tscl_h + I2C_Charac[I2C_speed].trise + + I2C_Charac[I2C_speed].tfall; + + if ((tscl >= clk_min) && (tscl <= clk_max) && + (tscl_h >= I2C_Charac[I2C_speed].hscl_min) && + (ti2cclk < tscl_h)) { + int32_t error = (int32_t)tscl - (int32_t)ti2cspeed; + + if (error < 0) { + error = -error; + } + + /* look for the timings with the lowest clock error */ + if ((uint32_t)error < prev_error) { + prev_error = (uint32_t)error; + I2c_valid_timing[count].scll = scll; + I2c_valid_timing[count].sclh = sclh; + ret = count; + } + } + } + } + } + } + + return ret; +} + +/* + * @brief Compute I2C timing according current I2C clock source and required + * I2C clock. + * @param clock_src_freq I2C clock source in Hz. + * @param i2c_freq Required I2C clock in Hz. + * @retval I2C timing or 0 in case of error. + */ +static uint32_t I2C_GetTiming(uint32_t clock_src_freq, uint32_t i2c_freq) { + uint32_t ret = 0; + uint32_t speed; + uint32_t idx; + + if ((clock_src_freq != 0U) && (i2c_freq != 0U)) { + for (speed = 0; speed <= (uint32_t)I2C_SPEED_FREQ_FAST_PLUS; speed++) { + if ((i2c_freq >= I2C_Charac[speed].freq_min) && + (i2c_freq <= I2C_Charac[speed].freq_max)) { + I2C_Compute_PRESC_SCLDEL_SDADEL(clock_src_freq, speed); + idx = I2C_Compute_SCLL_SCLH(clock_src_freq, speed); + + if (idx < I2C_VALID_TIMING_NBR) { + ret = ((I2c_valid_timing[idx].presc & 0x0FU) << 28) | + ((I2c_valid_timing[idx].tscldel & 0x0FU) << 20) | + ((I2c_valid_timing[idx].tsdadel & 0x0FU) << 16) | + ((I2c_valid_timing[idx].sclh & 0xFFU) << 8) | + ((I2c_valid_timing[idx].scll & 0xFFU) << 0); + } + break; + } + } + } + + return ret; +} + +void i2c_init_instance(uint16_t idx, i2c_instance_t *instance) { + if (i2c_handle[idx].Instance) { + return; + } + + GPIO_InitTypeDef GPIO_InitStructure; + + // configure CTP I2C SCL and SDA GPIO lines + GPIO_InitStructure.Mode = GPIO_MODE_AF_OD; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = + GPIO_SPEED_FREQ_LOW; // I2C is a KHz bus and low speed is still good into + // the low MHz + + GPIO_InitStructure.Alternate = instance->PinAF; + GPIO_InitStructure.Pin = instance->SclPin; + HAL_GPIO_Init(instance->SclPort, &GPIO_InitStructure); + + GPIO_InitStructure.Alternate = instance->PinAF; + GPIO_InitStructure.Pin = instance->SdaPin; + HAL_GPIO_Init(instance->SdaPort, &GPIO_InitStructure); + + i2c_handle[idx].Instance = instance->Instance; + i2c_handle[idx].Init.Timing = I2C_GetTiming(HAL_RCC_GetPCLK1Freq(), 400000); + i2c_handle[idx].Init.OwnAddress1 = 0xFE; // master + i2c_handle[idx].Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + i2c_handle[idx].Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + i2c_handle[idx].Init.OwnAddress2 = 0; + i2c_handle[idx].Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + i2c_handle[idx].Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + + if (HAL_OK != HAL_I2C_Init(&i2c_handle[idx])) { + ensure(secfalse, "I2C was not loaded properly."); + return; + } +} + +void i2c_init(void) { + // enable I2C clock + I2C_INSTANCE_1_CLK_EN(); + I2C_INSTANCE_1_SCL_CLK_EN(); + I2C_INSTANCE_1_SDA_CLK_EN(); + i2c_init_instance(0, &i2c_defs[0]); + +#ifdef I2C_INSTANCE_2 + I2C_INSTANCE_2_CLK_EN(); + I2C_INSTANCE_2_SCL_CLK_EN(); + I2C_INSTANCE_2_SDA_CLK_EN(); + i2c_init_instance(1, &i2c_defs[1]); +#endif +} + +void i2c_deinit(uint16_t idx) { + __HAL_RCC_I2C5_FORCE_RESET(); + if (i2c_handle[idx].Instance) { + HAL_I2C_DeInit(&i2c_handle[idx]); + i2c_handle[idx].Instance = NULL; + } +} + +void i2c_ensure_pin(GPIO_TypeDef *port, uint16_t GPIO_Pin, + GPIO_PinState PinState) { + HAL_GPIO_WritePin(port, GPIO_Pin, PinState); + while (HAL_GPIO_ReadPin(port, GPIO_Pin) != PinState) + ; +} + +void i2c_cycle(uint16_t idx) { + SET_BIT(*i2c_defs[idx].ResetReg, i2c_defs[idx].ResetBit); + CLEAR_BIT(*i2c_defs[idx].ResetReg, i2c_defs[idx].ResetBit); +} + +HAL_StatusTypeDef i2c_transmit(uint16_t idx, uint8_t addr, uint8_t *data, + uint16_t len, uint32_t timeout) { + return HAL_I2C_Master_Transmit(&i2c_handle[idx], addr, data, len, timeout); +} + +HAL_StatusTypeDef i2c_receive(uint16_t idx, uint8_t addr, uint8_t *data, + uint16_t len, uint32_t timeout) { + HAL_StatusTypeDef ret = + HAL_I2C_Master_Receive(&i2c_handle[idx], addr, data, len, timeout); +#ifdef USE_OPTIGA + if (idx == OPTIGA_I2C_INSTANCE) { + // apply GUARD_TIME as specified by the OPTIGA datasheet + // (only applies to the I2C bus to which the OPTIGA is connected) + hal_delay_us(50); + } +#endif + + return ret; +} + +HAL_StatusTypeDef i2c_mem_write(uint16_t idx, uint8_t addr, uint16_t mem_addr, + uint16_t mem_addr_size, uint8_t *data, + uint16_t len, uint32_t timeout) { + return HAL_I2C_Mem_Write(&i2c_handle[idx], addr, mem_addr, mem_addr_size, + data, len, timeout); +} +HAL_StatusTypeDef i2c_mem_read(uint16_t idx, uint8_t addr, uint16_t mem_addr, + uint16_t mem_addr_size, uint8_t *data, + uint16_t len, uint32_t timeout) { + return HAL_I2C_Mem_Read(&i2c_handle[idx], addr, mem_addr, mem_addr_size, data, + len, timeout); +} diff --git a/core/embed/trezorhal/stm32u5/i2c.h b/core/embed/trezorhal/stm32u5/i2c.h new file mode 120000 index 0000000000..d9235cabc4 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/i2c.h @@ -0,0 +1 @@ +../stm32f4/i2c.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/irq.h b/core/embed/trezorhal/stm32u5/irq.h new file mode 120000 index 0000000000..f2c8e555e6 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/irq.h @@ -0,0 +1 @@ +../stm32f4/irq.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/limited_util.s b/core/embed/trezorhal/stm32u5/limited_util.s new file mode 100644 index 0000000000..65adcd63f7 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/limited_util.s @@ -0,0 +1,145 @@ + .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! + cmp r0, r1 + beq .L_loop_end + .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 + .L_loop_end: + bx lr + + // Jump to address given in first argument R0 that points to next's stage's VTOR + // Clear memory and all registers before jump + .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 + 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, =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, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_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, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + 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 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, =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, =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, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =1 + msr control, r0 // jump to unprivileged mode + ldr r0, =0 + b . // loop forever + + .global MemManage_Handler + .type MemManage_Handler, STT_FUNC +MemManage_Handler: + ldr r2, =_sstack + mrs r1, msp + ldr r0, =_estack + msr msp, r0 + cmp r1, r2 + IT lt + bllt MemManage_Handler_SO + bl MemManage_Handler_MM + + .end diff --git a/core/embed/trezorhal/stm32u5/lowlevel.c b/core/embed/trezorhal/stm32u5/lowlevel.c new file mode 100644 index 0000000000..3e10cd462e --- /dev/null +++ b/core/embed/trezorhal/stm32u5/lowlevel.c @@ -0,0 +1,311 @@ +/* + * 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 . + */ + +#include STM32_HAL_H + +#include "lowlevel.h" +#include "common.h" +#include "flash.h" +#include "model.h" +#include TREZOR_BOARD + +#pragma GCC optimize( \ + "no-stack-protector") // applies to all functions in this file + +#if PRODUCTION +#define WANT_RDP_LEVEL (OB_RDP_LEVEL_2) +#define WANT_WRP_PAGE_START 2 +#define WANT_WRP_PAGE_END 7 +#else +#define WANT_RDP_LEVEL (OB_RDP_LEVEL_0) +#endif + +#ifdef VDD_3V3 +// BOR LEVEL 0: Reset level threshold is around 2.8 V +#define WANT_BOR_LEVEL (OB_BOR_LEVEL_4) +#define USE_PVD 1 +#elif VDD_1V8 +// BOR LEVEL 0: Reset level threshold is around 1.7 V +#define WANT_BOR_LEVEL (OB_BOR_LEVEL_0) +#else +#error "VDD_3V3 or VDD_1V8 must be defined" +#endif + +#if defined STM32U5A9xx | defined STM32U5G9xx +#define SEC_AREA_1_PAGE_START 0 +#define HDP_AREA_1_PAGE_END 1 +#define SEC_AREA_1_PAGE_END 0xFF +#define SEC_AREA_2_PAGE_START 0 +#define SEC_AREA_2_PAGE_END 0xFF +#elif define STM32U585xx +#define SEC_AREA_1_PAGE_START 0 +#define HDP_AREA_1_PAGE_END 1 +#define SEC_AREA_1_PAGE_END 0x7F +#define SEC_AREA_2_PAGE_START 0 +#define SEC_AREA_2_PAGE_END 0x7F +#else +#error Unknown MCU +#endif + +#define FLASH_OPTR_VALUE \ + (FLASH_OPTR_TZEN | FLASH_OPTR_PA15_PUPEN | FLASH_OPTR_nBOOT0 | \ + FLASH_OPTR_SRAM3_ECC | FLASH_OPTR_BKPRAM_ECC | FLASH_OPTR_DUALBANK | \ + FLASH_OPTR_WWDG_SW | FLASH_OPTR_IWDG_STOP | FLASH_OPTR_IWDG_STDBY | \ + FLASH_OPTR_IWDG_SW | FLASH_OPTR_SRAM_RST | FLASH_OPTR_nRST_SHDW | \ + FLASH_OPTR_nRST_STDBY | FLASH_OPTR_nRST_STOP | WANT_BOR_LEVEL | \ + (WANT_RDP_LEVEL << FLASH_OPTR_RDP_Pos)) + +#define FALSH_SECBOOTADD0R_VALUE \ + ((BOARDLOADER_START & 0xFFFFFF80) | FLASH_SECBOOTADD0R_BOOT_LOCK | 0x7C) +#define FLASH_SECWM1R1_VALUE \ + (SEC_AREA_1_PAGE_START << FLASH_SECWM1R1_SECWM1_PSTRT_Pos | \ + SEC_AREA_1_PAGE_END << FLASH_SECWM1R1_SECWM1_PEND_Pos | 0xFF00FF00) +#define FLASH_SECWM1R2_VALUE \ + (HDP_AREA_1_PAGE_END << FLASH_SECWM1R2_HDP1_PEND_Pos | \ + FLASH_SECWM1R2_HDP1EN | 0x7F007F00) +#define FLASH_SECWM2R1_VALUE \ + (SEC_AREA_2_PAGE_START << FLASH_SECWM1R1_SECWM1_PSTRT_Pos | \ + SEC_AREA_2_PAGE_END << FLASH_SECWM1R1_SECWM1_PEND_Pos | 0xFF00FF00) +#define FLASH_SECWM2R2_VALUE (0x7F007F00) + +secbool flash_check_option_bytes(void) { + flash_wait_and_clear_status_flags(); + // check values stored in flash interface registers + if (FLASH->OPTR != + FLASH_OPTR_VALUE) { // ignore bits 0 and 1 because they are control bits + return secfalse; + } + + if (FLASH->SECBOOTADD0R != FALSH_SECBOOTADD0R_VALUE) { + return secfalse; + } + +#if PRODUCTION + if (FLASH->WRP1AR != (WANT_WRP_PAGE_START | (WANT_WRP_PAGE_END << 16))) { + return secfalse; + } +#else + if (FLASH->WRP1AR != 0xFF00FFFF) { + return secfalse; + } +#endif + + if (FLASH->WRP1BR != 0xFF00FFFF) { + return secfalse; + } + if (FLASH->WRP2AR != 0xFF00FFFF) { + return secfalse; + } + if (FLASH->WRP2BR != 0xFF00FFFF) { + return secfalse; + } + + return sectrue; +} + +void flash_lock_option_bytes(void) { + FLASH->NSCR |= FLASH_NSCR_OPTLOCK; // lock the option bytes +} + +void flash_unlock_option_bytes(void) { + if ((FLASH->NSCR & FLASH_NSCR_OPTLOCK) == 0) { + return; // already unlocked + } + // reference RM0090 section 3.7.2 + // write the special sequence to unlock + FLASH->OPTKEYR = FLASH_OPTKEY1; + FLASH->OPTKEYR = FLASH_OPTKEY2; + while (FLASH->NSCR & FLASH_NSCR_OPTLOCK) + ; // wait until the flash option control register is unlocked +} + +uint32_t flash_set_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_VALUE; // WARNING: dev board safe unless you compile for + // PRODUCTION or change this value!!! + + FLASH->SECBOOTADD0R = FALSH_SECBOOTADD0R_VALUE; + +#if PRODUCTION + FLASH->WRP1AR = WANT_WRP_PAGE_START | (WANT_WRP_PAGE_END << 16); + FLASH->WRP1BR = 0xFF00FFFF; + FLASH->WRP2AR = 0xFF00FFFF; + FLASH->WRP2BR = 0xFF00FFFF; +#endif + + 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; +} + +void check_oem_keys(void) { + ensure(((FLASH_S->NSSR & FLASH_NSSR_OEM1LOCK) == 0) * sectrue, + "OEM1 KEY SET"); + ensure(((FLASH_S->NSSR & FLASH_NSSR_OEM2LOCK) == 0) * sectrue, + "OEM2 KEY SET"); +} + +secbool flash_configure_option_bytes(void) { + if (sectrue == flash_check_option_bytes()) { + return sectrue; // we DID NOT have to change the option bytes + } + + do { + flash_set_option_bytes(); + } while (sectrue != flash_check_option_bytes()); + + check_oem_keys(); + + return secfalse; // notify that we DID have to change the option bytes +} + +secbool flash_check_sec_area_ob(void) { + flash_wait_and_clear_status_flags(); + // check values stored in flash interface registers + + if (FLASH->SECWM1R1 != FLASH_SECWM1R1_VALUE) { + return secfalse; + } + if (FLASH->SECWM1R2 != FLASH_SECWM1R2_VALUE) { + return secfalse; + } + if (FLASH->SECWM2R1 != FLASH_SECWM2R1_VALUE) { + return secfalse; + } + if (FLASH->SECWM2R2 != FLASH_SECWM2R2_VALUE) { + return secfalse; + } + + return sectrue; +} + +uint32_t flash_set_sec_area_ob(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->SECWM1R1 = FLASH_SECWM1R1_VALUE; + FLASH->SECWM1R2 = FLASH_SECWM1R2_VALUE; + + FLASH->SECWM2R1 = FLASH_SECWM2R1_VALUE; + FLASH->SECWM2R2 = FLASH_SECWM2R2_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; +} + +secbool flash_configure_sec_area_ob(void) { + if (sectrue == flash_check_sec_area_ob()) { + return sectrue; // we DID NOT have to change the option bytes + } + + do { + flash_set_sec_area_ob(); + } while (sectrue != flash_check_sec_area_ob()); + + check_oem_keys(); + + return secfalse; // notify that we DID have to change the option bytes +} + +void periph_init(void) { + // STM32U5xx HAL library initialization: + // - configure the Flash prefetch, instruction and data caches + // - configure the Systick to generate an interrupt each 1 msec + // - set NVIC Group Priority to 4 + // - global MSP (MCU Support Package) initialization + HAL_Init(); + + // Enable GPIO clocks + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + +#ifdef USE_PVD + // enable the PVD (programmable voltage detector). + // select the "2.8V" threshold (level 5). + // this detector will be active regardless of the + // flash option byte BOR setting. + __HAL_RCC_PWR_CLK_ENABLE(); + PWR_PVDTypeDef pvd_config; + pvd_config.PVDLevel = PWR_PVDLEVEL_5; + pvd_config.Mode = PWR_PVD_MODE_IT_RISING_FALLING; + HAL_PWR_ConfigPVD(&pvd_config); + HAL_PWR_EnablePVD(); + NVIC_EnableIRQ(PVD_PVM_IRQn); +#endif +} + +secbool reset_flags_check(void) { +#if PRODUCTION + // this is effective enough that it makes development painful, so only use it + // for production. check the reset flags to assure that we arrive here due to + // a regular full power-on event, and not as a result of a lesser reset. + if ((RCC->CSR & (RCC_CSR_LPWRRSTF | RCC_CSR_WWDGRSTF | RCC_CSR_IWDGRSTF | + RCC_CSR_SFTRSTF | RCC_CSR_PINRSTF | RCC_CSR_BORRSTF | + RCC_CSR_OBLRSTF)) != (RCC_CSR_PINRSTF | RCC_CSR_BORRSTF)) { + return secfalse; + } +#endif + return sectrue; +} + +void reset_flags_reset(void) { + RCC->CSR |= RCC_CSR_RMVF; // clear the reset flags +} diff --git a/core/embed/trezorhal/stm32u5/mpu.c b/core/embed/trezorhal/stm32u5/mpu.c new file mode 100644 index 0000000000..e507edc909 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/mpu.c @@ -0,0 +1,258 @@ +/* + * 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 . + */ + +#include STM32_HAL_H +#include "common.h" +#include "flash.h" +#include "model.h" +#include "stm32u5xx_ll_cortex.h" + +#define ATTR_IDX_FLASH (0 << 1) +#define ATTR_IDX_FLASH_NON_CACHABLE (3 << 1) +#define ATTR_IDX_SRAM (1 << 1) +#define ATTR_IDX_PERIPH (2 << 1) +#define REGION_END(x) (((x) & ~0x1F) | 0x01) + +#define SHAREABILITY_FLASH (LL_MPU_ACCESS_NOT_SHAREABLE) +#define SHAREABILITY_SRAM \ + (LL_MPU_ACCESS_INNER_SHAREABLE | LL_MPU_ACCESS_OUTER_SHAREABLE) + +void mpu_config_off(void) { + // Disable MPU + HAL_MPU_Disable(); +} + +static uint32_t area_start(const flash_area_t* area) { + return (uint32_t)flash_area_get_address(area, 0, 0); +} + +static uint32_t area_end(const flash_area_t* area) { + uint32_t start = area_start(area); + uint32_t size = flash_area_get_size(area); + return start + size; +} + +void mpu_config_boardloader(void) { + // Disable MPU + HAL_MPU_Disable(); + + // flash memory + MPU->MAIR0 = 0xAA; + // internal ram + MPU->MAIR0 |= 0xAA << 8; + // peripherals + MPU->MAIR0 |= 0x00 << 16; + // non-cachable flash + MPU->MAIR0 |= 0x44 << 24; + + // Secret + MPU->RNR = MPU_REGION_NUMBER0; + MPU->RBAR = FLASH_BASE_S | LL_MPU_REGION_ALL_RW | SHAREABILITY_FLASH | + LL_MPU_INSTRUCTION_ACCESS_DISABLE; + MPU->RLAR = REGION_END(BOARDLOADER_START - 1) | ATTR_IDX_FLASH_NON_CACHABLE; + + // Flash boardloader (read-write) + MPU->RNR = MPU_REGION_NUMBER1; + MPU->RBAR = BOARDLOADER_START | LL_MPU_REGION_ALL_RW | SHAREABILITY_FLASH; + MPU->RLAR = REGION_END(BOOTLOADER_START - 1) | ATTR_IDX_FLASH; + + // Flash rest + MPU->RNR = MPU_REGION_NUMBER2; + MPU->RBAR = BOOTLOADER_START | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_FLASH; + MPU->RLAR = + REGION_END(FLASH_BASE_S + 0x400000 - 1) | ATTR_IDX_FLASH_NON_CACHABLE; + + // RAM (read-write, execute never) (SRAM1) + MPU->RNR = MPU_REGION_NUMBER3; + MPU->RBAR = SRAM1_BASE_S | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_SRAM; + MPU->RLAR = REGION_END(SRAM1_BASE_S + 0xC0000 - 1) | ATTR_IDX_SRAM; + + // RAM (read-write, execute never) (SRAM2, 3, 5, 6) + // reserve 256 bytes for stack overflow detection + MPU->RNR = MPU_REGION_NUMBER4; + MPU->RBAR = (SRAM2_BASE_S + 0x100) | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_SRAM; + MPU->RLAR = REGION_END(SRAM1_BASE_S + 0x2F0000 - 1) | ATTR_IDX_SRAM; + + // GFXMMU_VIRTUAL_BUFFERS (read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER5; + MPU->RBAR = GFXMMU_VIRTUAL_BUFFERS_BASE_S | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_SRAM; + MPU->RLAR = + REGION_END(GFXMMU_VIRTUAL_BUFFERS_BASE_S + 0x1000000 - 1) | ATTR_IDX_SRAM; + + // Peripherals (read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER6; + MPU->RBAR = + PERIPH_BASE_NS | LL_MPU_REGION_ALL_RW | LL_MPU_INSTRUCTION_ACCESS_DISABLE; + MPU->RLAR = REGION_END(PERIPH_BASE_NS + 0x20000000 - 1) | ATTR_IDX_PERIPH; + + // OTP (read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER7; + MPU->RBAR = FLASH_OTP_BASE | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_FLASH; + MPU->RLAR = REGION_END(FLASH_OTP_BASE + FLASH_OTP_SIZE - 1) | + ATTR_IDX_FLASH_NON_CACHABLE; + + // Non-secure Flash + MPU->RNR = MPU_REGION_NUMBER7; + MPU->RBAR = FLASH_BASE_NS | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_FLASH; + MPU->RLAR = + REGION_END(FLASH_BASE_NS + 0x400000 - 1) | ATTR_IDX_FLASH_NON_CACHABLE; + + // Enable MPU + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); +} + +void mpu_config_bootloader(void) { + // Disable MPU + HAL_MPU_Disable(); + + // flash memory + MPU->MAIR0 = 0xAA; + // internal ram + MPU->MAIR0 |= 0xAA << 8; + // peripherals + MPU->MAIR0 |= 0x00 << 16; + // non-cachable flash + MPU->MAIR0 |= 0x44 << 24; + + // Secret + boardloader + MPU->RNR = MPU_REGION_NUMBER0; + MPU->RBAR = FLASH_BASE_S | LL_MPU_REGION_ALL_RW | SHAREABILITY_FLASH; + MPU->RLAR = REGION_END(BOOTLOADER_START - 1) | ATTR_IDX_FLASH_NON_CACHABLE; + + // Bootloader (read-write) + MPU->RNR = MPU_REGION_NUMBER1; + MPU->RBAR = BOOTLOADER_START | LL_MPU_REGION_ALL_RW | SHAREABILITY_FLASH; + MPU->RLAR = REGION_END(area_start(&STORAGE_AREAS[0]) - 1) | ATTR_IDX_FLASH; + + // Flash firmware + storage (read-write, execute never), till flash end + MPU->RNR = MPU_REGION_NUMBER2; + MPU->RBAR = area_start(&STORAGE_AREAS[0]) | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_FLASH; + MPU->RLAR = + REGION_END(FLASH_BASE_S + 0x400000 - 1) | ATTR_IDX_FLASH_NON_CACHABLE; + + // RAM (read-write, execute never) (SRAM1) + MPU->RNR = MPU_REGION_NUMBER3; + MPU->RBAR = SRAM1_BASE_S | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_SRAM; + MPU->RLAR = REGION_END(SRAM1_BASE_S + 0xC0000 - 1) | ATTR_IDX_SRAM; + + // RAM (read-write, execute never) (SRAM2, 3, 5, 6) + // reserve 256 bytes for stack overflow detection + MPU->RNR = MPU_REGION_NUMBER4; + MPU->RBAR = (SRAM2_BASE_S + 0x100) | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_SRAM; + MPU->RLAR = REGION_END(SRAM1_BASE_S + 0x2F0000 - 1) | ATTR_IDX_SRAM; + + // GFXMMU_VIRTUAL_BUFFERS (read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER5; + MPU->RBAR = GFXMMU_VIRTUAL_BUFFERS_BASE_S | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_SRAM; + MPU->RLAR = + REGION_END(GFXMMU_VIRTUAL_BUFFERS_BASE_S + 0x1000000 - 1) | ATTR_IDX_SRAM; + + // Peripherals (read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER6; + MPU->RBAR = + PERIPH_BASE_S | LL_MPU_REGION_ALL_RW | LL_MPU_INSTRUCTION_ACCESS_DISABLE; + MPU->RLAR = REGION_END(PERIPH_BASE_S + 0x10000000 - 1) | ATTR_IDX_PERIPH; + + // OTP (read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER7; + MPU->RBAR = FLASH_OTP_BASE | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_FLASH; + MPU->RLAR = REGION_END(FLASH_OTP_BASE + FLASH_OTP_SIZE - 1) | + ATTR_IDX_FLASH_NON_CACHABLE; + + // Enable MPU + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); +} + +void mpu_config_firmware(void) { + // Disable MPU + HAL_MPU_Disable(); + + // flash memory + MPU->MAIR0 = 0xAA; + // internal ram + MPU->MAIR0 |= 0xAA << 8; + // peripherals + MPU->MAIR0 |= 0x00 << 16; + // non-cachable flash + MPU->MAIR0 |= 0x44 << 24; + + // bootloader + boardloader: no access, execute never: need to do everything + // before turning on MPU + + // Storage (read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER0; + MPU->RBAR = area_start(&STORAGE_AREAS[0]) | LL_MPU_REGION_ALL_RW | + SHAREABILITY_FLASH | LL_MPU_INSTRUCTION_ACCESS_DISABLE; + MPU->RLAR = REGION_END(FIRMWARE_START - 1) | ATTR_IDX_FLASH_NON_CACHABLE; + + // Flash firmware (read-write) + MPU->RNR = MPU_REGION_NUMBER1; + MPU->RBAR = (FIRMWARE_START) | LL_MPU_REGION_ALL_RO | SHAREABILITY_FLASH; + MPU->RLAR = REGION_END(area_end(&FIRMWARE_AREA) - 1) | ATTR_IDX_FLASH; + + // RAM (read-write, execute never) (SRAM1) + MPU->RNR = MPU_REGION_NUMBER2; + MPU->RBAR = SRAM1_BASE_S | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_SRAM; + MPU->RLAR = REGION_END(SRAM1_BASE_S + 0xC0000 - 1) | ATTR_IDX_SRAM; + + // RAM (read-write, execute never) (SRAM2, 3, 5, 6) + // reserve 256 bytes for stack overflow detection + MPU->RNR = MPU_REGION_NUMBER3; + MPU->RBAR = (SRAM2_BASE_S + 0x100) | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_SRAM; + MPU->RLAR = REGION_END(SRAM1_BASE_S + 0x2F0000 - 1) | ATTR_IDX_SRAM; + + // GFXMMU_VIRTUAL_BUFFERS (read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER4; + MPU->RBAR = GFXMMU_VIRTUAL_BUFFERS_BASE_S | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_SRAM; + MPU->RLAR = + REGION_END(GFXMMU_VIRTUAL_BUFFERS_BASE_S + 0x1000000 - 1) | ATTR_IDX_SRAM; + + // Peripherals (read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER5; + MPU->RBAR = + PERIPH_BASE_S | LL_MPU_REGION_ALL_RW | LL_MPU_INSTRUCTION_ACCESS_DISABLE; + MPU->RLAR = REGION_END(PERIPH_BASE_S + 0x10000000 - 1) | ATTR_IDX_PERIPH; + + // OTP (read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER6; + MPU->RBAR = FLASH_OTP_BASE | LL_MPU_REGION_ALL_RW | + LL_MPU_INSTRUCTION_ACCESS_DISABLE | SHAREABILITY_FLASH; + MPU->RLAR = REGION_END(FLASH_OTP_BASE + FLASH_OTP_SIZE - 1) | + ATTR_IDX_FLASH_NON_CACHABLE; + + // Enable MPU + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + + __asm__ volatile("dsb"); + __asm__ volatile("isb"); +} diff --git a/core/embed/trezorhal/stm32u5/platform.c b/core/embed/trezorhal/stm32u5/platform.c new file mode 100644 index 0000000000..0a16a93ba3 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/platform.c @@ -0,0 +1,212 @@ +/* + * 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 . + */ + +#include STM32_HAL_H + +#include "platform.h" +#include "rng.h" +#include TREZOR_BOARD + +const uint8_t AHBPrescTable[16] = {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, + 1U, 2U, 3U, 4U, 6U, 7U, 8U, 9U}; +const uint8_t APBPrescTable[8] = {0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U}; +const uint32_t MSIRangeTable[16] = {48000000U, 24000000U, 16000000U, 12000000U, + 4000000U, 2000000U, 1330000U, 1000000U, + 3072000U, 1536000U, 1024000U, 768000U, + 400000U, 200000U, 133000U, 100000U}; +typedef struct { + uint32_t freq; + uint32_t pllq; + uint32_t pllp; + uint32_t pllm; + uint32_t plln; +} clock_conf_t; + +#if defined STM32U5 +#define DEFAULT_FREQ 160U +#define DEFAULT_PLLM 1 +#define DEFAULT_PLLN (10 * PLLN_COEF) // mult by 10 +#define DEFAULT_PLLR 1U // division by 1 +#define DEFAULT_PLLQ 1U // division by 1 +#define DEFAULT_PLLP 5U // division by 5 +#else +#error Unsupported MCU +#endif + +uint32_t SystemCoreClock = DEFAULT_FREQ * 1000000U; + +// PLLCLK = ((HSE / PLLM) * PLLN) / PLLR +#ifdef HSE_16MHZ +#define PLLN_COEF 1U +#elif defined HSE_8MHZ +#define PLLN_COEF 2U +#else +#error Unsupported HSE frequency +#endif + +// assuming HSE 16 MHz +clock_conf_t clock_conf[1] = { + { + // clk = ((16MHz / 1) * 10) / 1 = 160 MHz + .freq = 160, + .pllp = 1, + .pllq = 1, + .pllm = 1, + .plln = 10 * PLLN_COEF, + }, +}; + +#pragma GCC optimize( \ + "no-stack-protector") // applies to all functions in this file + +void SystemInit(void) { + // set flash wait states for an increasing HCLK frequency + + FLASH->ACR = FLASH_ACR_LATENCY_5WS; + // wait until the new wait state config takes effect -- per section 3.5.1 + // guidance + while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_5WS) + ; + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set MSION bit */ + RCC->CR = RCC_CR_MSISON; + + /* Reset CFGR register */ + RCC->CFGR1 = 0U; + RCC->CFGR2 = 0U; + RCC->CFGR3 = 0U; + + /* Reset HSEON, CSSON , HSION, PLLxON bits */ + RCC->CR &= ~(RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_PLL1ON | RCC_CR_PLL2ON | + RCC_CR_PLL3ON | RCC_CR_HSI48ON); + + /* Reset PLLCFGR register */ + RCC->PLL1CFGR = 0U; + + /* Reset HSEBYP bit */ + RCC->CR &= ~(RCC_CR_HSEBYP); + + /* Disable all interrupts */ + RCC->CIER = 0U; + + __HAL_RCC_PWR_CLK_ENABLE(); + + MODIFY_REG(PWR->VOSR, (PWR_VOSR_VOS | PWR_VOSR_BOOSTEN), + PWR_REGULATOR_VOLTAGE_SCALE1); + while (HAL_IS_BIT_CLR(PWR->VOSR, PWR_VOSR_VOSRDY)) + ; + while (HAL_IS_BIT_CLR(PWR->SVMSR, PWR_SVMSR_ACTVOSRDY)) + ; + + __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); + while (READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0U) + ; + + __HAL_RCC_PLL_CONFIG(RCC_PLLSOURCE_HSE, RCC_PLLMBOOST_DIV1, DEFAULT_PLLM, + DEFAULT_PLLN, DEFAULT_PLLP, DEFAULT_PLLQ, DEFAULT_PLLR); + + __HAL_RCC_PLL_FRACN_DISABLE(); + + __HAL_RCC_PLL_VCIRANGE(RCC_PLLVCIRANGE_1); + + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVR); + + __HAL_RCC_PLL_ENABLE(); + while (READ_BIT(RCC->CR, RCC_CR_PLL1RDY) == 0U) + ; + + __HAL_RCC_HSI48_ENABLE(); + while (READ_BIT(RCC->CR, RCC_CR_HSI48RDY) == 0U) + ; + + /** Initializes the CPU, AHB and APB buses clocks + */ + FLASH->ACR = FLASH_ACR_LATENCY_4WS; + // wait until the new wait state config takes effect -- per section 3.5.1 + // guidance + while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_4WS) + ; + MODIFY_REG(RCC->CFGR3, RCC_CFGR3_PPRE3, RCC_HCLK_DIV1); + MODIFY_REG(RCC->CFGR2, RCC_CFGR2_PPRE2, ((RCC_HCLK_DIV1) << 4)); + MODIFY_REG(RCC->CFGR2, RCC_CFGR2_PPRE1, RCC_HCLK_DIV1); + MODIFY_REG(RCC->CFGR2, RCC_CFGR2_HPRE, RCC_SYSCLK_DIV1); + + MODIFY_REG(RCC->CFGR1, RCC_CFGR1_SW, RCC_SYSCLKSOURCE_PLLCLK); + + /* + * Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral + */ + HAL_PWREx_DisableUCPDDeadBattery(); + + /* + * Switch to SMPS regulator instead of LDO + */ + SET_BIT(PWR->CR3, PWR_CR3_REGSEL); + /* Wait until system switch on new regulator */ + while (HAL_IS_BIT_CLR(PWR->SVMSR, PWR_SVMSR_REGS)) + ; + + __HAL_RCC_PWR_CLK_DISABLE(); + + // this will be overriden by static initialization + SystemCoreClock = DEFAULT_FREQ * 1000000U; + + // enable clock security system, HSE clock, and main PLL + RCC->CR |= RCC_CR_CSSON; + + // turn off the HSI as it is now unused (it will be turned on again + // automatically if a clock security failure occurs) + RCC->CR &= ~RCC_CR_HSION; + // wait until ths HSI is off + while ((RCC->CR & RCC_CR_HSION) == RCC_CR_HSION) + ; + + // TODO turn off MSI? + + // init the TRNG peripheral + rng_init(); + + // set CP10 and CP11 to enable full access to the fpu coprocessor; + SCB->CPACR |= + ((3UL << 20U) | (3UL << 22U)); /* set CP10 and CP11 Full Access */ + +#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + SCB_NS->CPACR |= + ((3UL << 20U) | (3UL << 22U)); /* set CP10 and CP11 Full Access */ +#endif + + // enable instruction cache in default 2-way mode + ICACHE->CR = ICACHE_CR_EN; +} + +void drop_privileges(void) { + // jump to unprivileged mode + // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html + __asm__ volatile("msr control, %0" ::"r"(0x1)); + __asm__ volatile("isb"); +} + +// from util.s +extern void shutdown_privileged(void); + +void PVD_PVM_IRQHandler(void) { + TIM1->CCR1 = 0; // turn off display backlight + shutdown_privileged(); +} diff --git a/core/embed/trezorhal/stm32u5/platform.h b/core/embed/trezorhal/stm32u5/platform.h new file mode 100644 index 0000000000..233a367dd8 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/platform.h @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +#ifndef TREZORHAL_STM32_H +#define TREZORHAL_STM32_H + +#include STM32_HAL_H +#include + +#define SENSITIVE __attribute__((section(".sensitive"))) + +typedef enum { + CLOCK_160_MHZ = 0, +} clock_settings_t; + +void set_core_clock(clock_settings_t settings); +void ensure_compatible_settings(void); +void drop_privileges(void); + +// the following functions are defined in util.s +void memset_reg(volatile void *start, volatile void *stop, uint32_t val); +void jump_to(uint32_t address); +void jump_to_unprivileged(uint32_t address); +void jump_to_with_flag(uint32_t address, uint32_t register_flag); + +extern uint32_t __stack_chk_guard; + +// this deletes all secrets and SRAM2 where stack is located +// to prevent stack smashing error, do not return from function calling this +static inline void __attribute__((always_inline)) delete_secrets(void) { + // Disable SAES peripheral clock, so that we don't get tamper events + __HAL_RCC_SAES_CLK_DISABLE(); + + // Erase all + TAMP->CR2 |= TAMP_CR2_BKERASE; +} + +void check_oem_keys(void); + +#endif // TREZORHAL_STM32_H diff --git a/core/embed/trezorhal/stm32u5/random_delays.c b/core/embed/trezorhal/stm32u5/random_delays.c new file mode 120000 index 0000000000..eb47d77293 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/random_delays.c @@ -0,0 +1 @@ +../stm32f4/random_delays.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/rng.c b/core/embed/trezorhal/stm32u5/rng.c new file mode 120000 index 0000000000..f16159d787 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/rng.c @@ -0,0 +1 @@ +../stm32f4/rng.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/sbu.c b/core/embed/trezorhal/stm32u5/sbu.c new file mode 120000 index 0000000000..54c434947d --- /dev/null +++ b/core/embed/trezorhal/stm32u5/sbu.c @@ -0,0 +1 @@ +../stm32f4/sbu.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/secret.c b/core/embed/trezorhal/stm32u5/secret.c new file mode 100644 index 0000000000..aac7708066 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/secret.c @@ -0,0 +1,162 @@ +#include "secret.h" +#include +#include "common.h" +#include "flash.h" +#include "model.h" +#include "rng.h" + +static secbool bootloader_locked_set = secfalse; +static secbool bootloader_locked = secfalse; + +static secbool verify_header(void) { + uint8_t header[SECRET_HEADER_LEN] = {0}; + + memcpy(header, flash_area_get_address(&SECRET_AREA, 0, SECRET_HEADER_LEN), + SECRET_HEADER_LEN); + + bootloader_locked = + memcmp(header, SECRET_HEADER_MAGIC, 4) == 0 ? sectrue : secfalse; + bootloader_locked_set = sectrue; + return bootloader_locked; +} + +secbool secret_bootloader_locked(void) { + if (bootloader_locked_set != sectrue) { + // Set bootloader_locked. + verify_header(); + } + + return bootloader_locked; +} + +void secret_write_header(void) { + uint8_t header[SECRET_HEADER_LEN] = {0}; + memcpy(header, SECRET_HEADER_MAGIC, 4); + secret_write(header, 0, SECRET_HEADER_LEN); +} + +void secret_write(uint8_t *data, uint32_t offset, uint32_t len) { + ensure(flash_unlock_write(), "secret write"); + for (int i = 0; i < len / 16; i++) { + ensure(flash_area_write_quadword(&SECRET_AREA, offset + (i * 16), + (uint32_t *)&data[(i * 16)]), + "secret write"); + } + ensure(flash_lock_write(), "secret write"); +} + +secbool secret_read(uint8_t *data, uint32_t offset, uint32_t len) { + if (sectrue != verify_header()) { + return secfalse; + } + + memcpy(data, flash_area_get_address(&SECRET_AREA, offset, len), len); + + return sectrue; +} + +void secret_hide(void) { + FLASH->SECHDPCR |= FLASH_SECHDPCR_HDP1_ACCDIS_Msk; + FLASH->SECHDPCR |= FLASH_SECHDPCR_HDP2_ACCDIS_Msk; +} + +void secret_bhk_lock(void) { + TAMP_S->SECCFGR = 8 << TAMP_SECCFGR_BKPRWSEC_Pos | TAMP_SECCFGR_BHKLOCK; +} + +secbool secret_bhk_locked(void) { + return ((TAMP_S->SECCFGR & TAMP_SECCFGR_BHKLOCK) == TAMP_SECCFGR_BHKLOCK) * + sectrue; +} + +void secret_bhk_provision(void) { + uint32_t secret[SECRET_BHK_LEN / sizeof(uint32_t)] = {0}; + secbool ok = + secret_read((uint8_t *)secret, SECRET_BHK_OFFSET, SECRET_BHK_LEN); + + volatile uint32_t *reg1 = &TAMP->BKP0R; + if (sectrue == ok) { + for (int i = 0; i < 8; i++) { + *reg1 = ((uint32_t *)secret)[i]; + reg1++; + } + } else { + for (int i = 0; i < 8; i++) { + *reg1 = 0; + reg1++; + } + } +} + +void secret_bhk_regenerate(void) { + ensure(flash_area_erase(&BHK_AREA, NULL), "Failed regenerating BHK"); + ensure(flash_unlock_write(), "Failed regenerating BHK"); + for (int i = 0; i < 2; i++) { + uint32_t val[4] = {0}; + for (int j = 0; j < 4; j++) { + val[j] = rng_get(); + } + ensure(flash_area_write_quadword(&BHK_AREA, i * 4 * sizeof(uint32_t), val), + "Failed regenerating BHK"); + } + ensure(flash_lock_write(), "Failed regenerating BHK"); +} + +secbool secret_optiga_present(void) { + uint8_t *optiga_secret = (uint8_t *)flash_area_get_address( + &SECRET_AREA, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); + + int optiga_secret_empty_bytes = 0; + + for (int i = 0; i < SECRET_OPTIGA_KEY_LEN; i++) { + if (optiga_secret[i] == 0xFF) { + optiga_secret_empty_bytes++; + } + } + return sectrue * (optiga_secret_empty_bytes != SECRET_OPTIGA_KEY_LEN); +} + +void secret_optiga_backup(void) { + uint32_t secret[SECRET_OPTIGA_KEY_LEN / sizeof(uint32_t)] = {0}; + secbool ok = secret_read((uint8_t *)secret, SECRET_OPTIGA_KEY_OFFSET, + SECRET_OPTIGA_KEY_LEN); + + volatile uint32_t *reg1 = &TAMP->BKP8R; + if (sectrue == ok) { + for (int i = 0; i < 8; i++) { + *reg1 = ((uint32_t *)secret)[i]; + reg1++; + } + } else { + for (int i = 0; i < 8; i++) { + *reg1 = 0; + reg1++; + } + } +} + +secbool secret_optiga_extract(uint8_t *dest) { + bool all_zero = true; + volatile uint32_t *reg1 = &TAMP->BKP8R; + for (int i = 0; i < 8; i++) { + uint32_t val = *reg1++; + + if (val != 0) { + all_zero = false; + } + + for (int j = 0; j < 4; j++) { + dest[i * 4 + j] = (val >> (j * 8)) & 0xFF; + } + } + + return all_zero ? secfalse : sectrue; +} + +void secret_optiga_hide(void) { + volatile uint32_t *reg1 = &TAMP->BKP8R; + for (int i = 0; i < 8; i++) { + *reg1 = 0; + reg1++; + } +} diff --git a/core/embed/trezorhal/stm32u5/secure_aes.c b/core/embed/trezorhal/stm32u5/secure_aes.c new file mode 100644 index 0000000000..9fd964e67c --- /dev/null +++ b/core/embed/trezorhal/stm32u5/secure_aes.c @@ -0,0 +1,117 @@ +/* + * 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 . + */ + +#include +#include STM32_HAL_H + +#include +#include + +secbool secure_aes_init(void) { + RCC_OscInitTypeDef osc_init_def = {0}; + osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_SHSI; + osc_init_def.SHSIState = RCC_SHSI_ON; + + // Enable SHSI clock + if (HAL_RCC_OscConfig(&osc_init_def) != HAL_OK) { + return secfalse; + } + + // Enable SAES peripheral clock + __HAL_RCC_SAES_CLK_ENABLE(); + + return sectrue; +} + +static void secure_aes_load_bhk(void) { + TAMP->BKP7R; + TAMP->BKP6R; + TAMP->BKP5R; + TAMP->BKP4R; + TAMP->BKP3R; + TAMP->BKP2R; + TAMP->BKP1R; + TAMP->BKP0R; +} + +secbool secure_aes_encrypt(uint32_t* input, size_t size, uint32_t* output) { + CRYP_HandleTypeDef hcryp = {0}; + uint32_t iv[] = {0, 0, 0, 0}; + + hcryp.Instance = SAES; + hcryp.Init.DataType = CRYP_NO_SWAP; + hcryp.Init.KeySelect = CRYP_KEYSEL_HSW; + hcryp.Init.KeySize = CRYP_KEYSIZE_256B; + hcryp.Init.pKey = NULL; + hcryp.Init.pInitVect = iv; + hcryp.Init.Algorithm = CRYP_AES_ECB; + hcryp.Init.Header = NULL; + hcryp.Init.HeaderSize = 0; + hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD; + hcryp.Init.HeaderWidthUnit = CRYP_HEADERWIDTHUNIT_BYTE; + hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS; + hcryp.Init.KeyMode = CRYP_KEYMODE_NORMAL; + + if (HAL_CRYP_Init(&hcryp) != HAL_OK) { + return secfalse; + } + + secure_aes_load_bhk(); + + if (HAL_CRYP_Encrypt(&hcryp, input, size, output, HAL_MAX_DELAY) != HAL_OK) { + return secfalse; + } + + HAL_CRYP_DeInit(&hcryp); + + return sectrue; +} + +secbool secure_aes_decrypt(uint32_t* input, size_t size, uint32_t* output) { + CRYP_HandleTypeDef hcryp = {0}; + uint32_t iv[] = {0, 0, 0, 0}; + + hcryp.Instance = SAES; + hcryp.Init.DataType = CRYP_NO_SWAP; + hcryp.Init.KeySelect = CRYP_KEYSEL_HSW; + hcryp.Init.KeySize = CRYP_KEYSIZE_256B; + hcryp.Init.pKey = NULL; + hcryp.Init.pInitVect = iv; + hcryp.Init.Algorithm = CRYP_AES_ECB; + hcryp.Init.Header = NULL; + hcryp.Init.HeaderSize = 0; + hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_BYTE; + hcryp.Init.HeaderWidthUnit = CRYP_HEADERWIDTHUNIT_BYTE; + hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS; + hcryp.Init.KeyMode = CRYP_KEYMODE_NORMAL; + + if (HAL_CRYP_Init(&hcryp) != HAL_OK) { + return secfalse; + } + + secure_aes_load_bhk(); + + if (HAL_CRYP_Decrypt(&hcryp, input, size, output, HAL_MAX_DELAY) != HAL_OK) { + return secfalse; + } + + HAL_CRYP_DeInit(&hcryp); + + return sectrue; +} diff --git a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h new file mode 100644 index 0000000000..e5d66e2faa --- /dev/null +++ b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h @@ -0,0 +1,563 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32u5xx_hal_conf.h + * @author MCD Application Team + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32U5xx_HAL_CONF_H +#define STM32U5xx_HAL_CONF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +#define USE_USB_HS +#define USE_USB_HS_INTERNAL_PHY + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ + +#define HAL_MODULE_ENABLED + +/*#define HAL_ADC_MODULE_ENABLED */ +/*#define HAL_MDF_MODULE_ENABLED */ +/*#define HAL_COMP_MODULE_ENABLED */ +/*#define HAL_CORDIC_MODULE_ENABLED */ +/*#define HAL_CRC_MODULE_ENABLED */ +/*#define HAL_CRYP_MODULE_ENABLED */ +/*#define HAL_DAC_MODULE_ENABLED */ +#define HAL_DMA2D_MODULE_ENABLED +#define HAL_DSI_MODULE_ENABLED +/*#define HAL_FDCAN_MODULE_ENABLED */ +/*#define HAL_FMAC_MODULE_ENABLED */ +#define HAL_GFXMMU_MODULE_ENABLED +/*#define HAL_GPU2D_MODULE_ENABLED */ +#define HAL_GTZC_MODULE_ENABLED +/*#define HAL_HASH_MODULE_ENABLED */ +/*#define HAL_HRTIM_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +#define HAL_I2C_MODULE_ENABLED +/*#define HAL_I2S_MODULE_ENABLED */ +/*#define HAL_LPTIM_MODULE_ENABLED */ +#define HAL_LTDC_MODULE_ENABLED +/*#define HAL_NAND_MODULE_ENABLED */ +/*#define HAL_NOR_MODULE_ENABLED */ +/*#define HAL_OPAMP_MODULE_ENABLED */ +/*#define HAL_OSPI_MODULE_ENABLED */ +/*#define HAL_OTFDEC_MODULE_ENABLED */ +/*#define HAL_PKA_MODULE_ENABLED */ +/*#define HAL_QSPI_MODULE_ENABLED */ +/*#define HAL_RNG_MODULE_ENABLED */ +#define HAL_RTC_MODULE_ENABLED +/*#define HAL_SAI_MODULE_ENABLED */ +#define HAL_CRYP_MODULE_ENABLED +/*#define HAL_SD_MODULE_ENABLED */ +/*#define HAL_MMC_MODULE_ENABLED */ +/*#define HAL_SMARTCARD_MODULE_ENABLED */ +/*#define HAL_SMBUS_MODULE_ENABLED */ +/*#define HAL_SPI_MODULE_ENABLED */ +/*#define HAL_SRAM_MODULE_ENABLED */ +/*#define HAL_TIM_MODULE_ENABLED */ +/*#define HAL_TSC_MODULE_ENABLED */ +/*#define HAL_RAMCFG_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/*#define HAL_USART_MODULE_ENABLED */ +/*#define HAL_WWDG_MODULE_ENABLED */ +/*#define HAL_DCMI_MODULE_ENABLED */ +/*#define HAL_PSSI_MODULE_ENABLED */ +#define HAL_ICACHE_MODULE_ENABLED +/*#define HAL_DCACHE_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +/*#define HAL_HCD_MODULE_ENABLED */ +/*#define HAL_XSPI_MODULE_ENABLED */ + +#define HAL_GPIO_MODULE_ENABLED +#define HAL_EXTI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ########################## Oscillator Values adaptation + * ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your + * application. This value is used by the RCC HAL module to compute the system + * frequency (when HSE is used as system clock source, directly or through the + * PLL). + */ +#if !defined(HSE_VALUE) +#define HSE_VALUE 16000000UL /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined(HSE_STARTUP_TIMEOUT) +#define HSE_STARTUP_TIMEOUT 100UL /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined(MSI_VALUE) +#define MSI_VALUE 4000000UL /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system + * frequency (when HSI is used as system clock source, directly or through the + * PLL). + */ +#if !defined(HSI_VALUE) +#define HSI_VALUE 16000000UL /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI48) value for USB FS, SDMMC and + * RNG. This internal oscillator is mainly dedicated to provide a high precision + * clock to the USB peripheral by means of a special Clock Recovery System (CRS) + * circuitry. When the CRS is not used, the HSI48 RC oscillator runs on it + * default frequency which is subject to manufacturing process variations. + */ +#if !defined(HSI48_VALUE) +#define HSI48_VALUE \ + 48000000UL /*!< Value of the Internal High Speed oscillator for USB \ + FS/SDMMC/RNG in Hz. The real value my vary depending on \ + manufacturing process variations.*/ +#endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined(LSI_VALUE) +#define LSI_VALUE 32000UL /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz \ + The real value may vary depending on the \ + variations in voltage and temperature.*/ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system + * frequency + */ +#if !defined(LSE_VALUE) +#define LSE_VALUE \ + 32768UL /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined(LSE_STARTUP_TIMEOUT) +#define LSE_STARTUP_TIMEOUT 5000UL /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 + * clock source frequency. + */ +#if !defined(EXTERNAL_SAI1_CLOCK_VALUE) +#define EXTERNAL_SAI1_CLOCK_VALUE \ + 48000UL /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ + +#define VDD_VALUE 3300UL /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY \ + (15UL) /*!< tick interrupt priority (lowest by default) */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U /*!< Enable prefetch */ + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ + +/* #define USE_FULL_ASSERT 1U */ + +/* ################## Register callback feature configuration ############### */ +/** + * @brief Set below the peripheral configuration to "1U" to add the support + * of HAL callback registration/unregistration feature for the HAL + * driver(s). This allows user application to provide specific callback + * functions thanks to HAL_PPP_RegisterCallback() rather than overwriting + * the default weak callback functions (see each stm32u5xx_hal_ppp.h file + * for possible callback identifiers defined in HAL_PPP_CallbackIDTypeDef + * for each PPP peripheral). + */ +#define USE_HAL_ADC_REGISTER_CALLBACKS \ + 0U /* ADC register callback disabled */ +#define USE_HAL_COMP_REGISTER_CALLBACKS \ + 0U /* COMP register callback disabled */ +#define USE_HAL_CORDIC_REGISTER_CALLBACKS \ + 0U /* CORDIC register callback disabled */ +#define USE_HAL_CRYP_REGISTER_CALLBACKS \ + 0U /* CRYP register callback disabled */ +#define USE_HAL_DAC_REGISTER_CALLBACKS \ + 0U /* DAC register callback disabled */ +#define USE_HAL_DCMI_REGISTER_CALLBACKS \ + 0U /* DCMI register callback disabled */ +#define USE_HAL_DMA2D_REGISTER_CALLBACKS \ + 0U /* DMA2D register callback disabled */ +#define USE_HAL_DSI_REGISTER_CALLBACKS \ + 0U /* DSI register callback disabled */ +#define USE_HAL_ETH_REGISTER_CALLBACKS \ + 0U /* ETH register callback disabled */ +#define USE_HAL_FDCAN_REGISTER_CALLBACKS \ + 0U /* FDCAN register callback disabled */ +#define USE_HAL_FMAC_REGISTER_CALLBACKS \ + 0U /* FMAC register callback disabled */ +#define USE_HAL_HASH_REGISTER_CALLBACKS \ + 0U /* HASH register callback disabled */ +#define USE_HAL_HCD_REGISTER_CALLBACKS \ + 0U /* HCD register callback disabled */ +#define USE_HAL_GFXMMU_REGISTER_CALLBACKS \ + 0U /* GFXMMU register callback disabled */ +#define USE_HAL_GPU2D_REGISTER_CALLBACKS \ + 0U /* GPU2D register callback disabled */ +#define USE_HAL_I2C_REGISTER_CALLBACKS \ + 0U /* I2C register callback disabled */ +#define USE_HAL_IWDG_REGISTER_CALLBACKS \ + 0U /* IWDG register callback disabled */ +#define USE_HAL_IRDA_REGISTER_CALLBACKS \ + 0U /* IRDA register callback disabled */ +#define USE_HAL_LPTIM_REGISTER_CALLBACKS \ + 0U /* LPTIM register callback disabled */ +#define USE_HAL_LTDC_REGISTER_CALLBACKS \ + 0U /* LTDC register callback disabled */ +#define USE_HAL_MDF_REGISTER_CALLBACKS \ + 0U /* MDF register callback disabled */ +#define USE_HAL_MMC_REGISTER_CALLBACKS \ + 0U /* MMC register callback disabled */ +#define USE_HAL_NAND_REGISTER_CALLBACKS \ + 0U /* NAND register callback disabled */ +#define USE_HAL_NOR_REGISTER_CALLBACKS \ + 0U /* NOR register callback disabled */ +#define USE_HAL_OPAMP_REGISTER_CALLBACKS \ + 0U /* MDIO register callback disabled */ +#define USE_HAL_OTFDEC_REGISTER_CALLBACKS \ + 0U /* OTFDEC register callback disabled */ +#define USE_HAL_PCD_REGISTER_CALLBACKS \ + 0U /* PCD register callback disabled */ +#define USE_HAL_PKA_REGISTER_CALLBACKS \ + 0U /* PKA register callback disabled */ +#define USE_HAL_RAMCFG_REGISTER_CALLBACKS \ + 0U /* RAMCFG register callback disabled */ +#define USE_HAL_RNG_REGISTER_CALLBACKS \ + 0U /* RNG register callback disabled */ +#define USE_HAL_RTC_REGISTER_CALLBACKS \ + 0U /* RTC register callback disabled */ +#define USE_HAL_SAI_REGISTER_CALLBACKS \ + 0U /* SAI register callback disabled */ +#define USE_HAL_SD_REGISTER_CALLBACKS \ + 0U /* SD register callback disabled */ +#define USE_HAL_SDRAM_REGISTER_CALLBACKS \ + 0U /* SDRAM register callback disabled */ +#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS \ + 0U /* SMARTCARD register callback disabled */ +#define USE_HAL_SMBUS_REGISTER_CALLBACKS \ + 0U /* SMBUS register callback disabled */ +#define USE_HAL_SPI_REGISTER_CALLBACKS \ + 0U /* SPI register callback disabled */ +#define USE_HAL_SRAM_REGISTER_CALLBACKS \ + 0U /* SRAM register callback disabled */ +#define USE_HAL_TIM_REGISTER_CALLBACKS \ + 0U /* TIM register callback disabled */ +#define USE_HAL_TSC_REGISTER_CALLBACKS \ + 0U /* TSC register callback disabled */ +#define USE_HAL_UART_REGISTER_CALLBACKS \ + 0U /* UART register callback disabled */ +#define USE_HAL_USART_REGISTER_CALLBACKS \ + 0U /* USART register callback disabled */ +#define USE_HAL_WWDG_REGISTER_CALLBACKS \ + 0U /* WWDG register callback disabled */ +#define USE_HAL_OSPI_REGISTER_CALLBACKS \ + 0U /* OSPI register callback disabled */ +/* ################## SPI peripheral configuration ########################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ +#define USE_SPI_CRC 0U + +/* ################## SDMMC peripheral configuration ######################### + */ + +#define USE_SD_TRANSCEIVER 0U /*!< use uSD Transceiver */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED +#include "stm32u5xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED +#include "stm32u5xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_ICACHE_MODULE_ENABLED +#include "stm32u5xx_hal_icache.h" +#endif /* HAL_ICACHE_MODULE_ENABLED */ + +#ifdef HAL_DCACHE_MODULE_ENABLED +#include "stm32u5xx_hal_dcache.h" +#endif /* HAL_DCACHE_MODULE_ENABLED */ + +#ifdef HAL_GTZC_MODULE_ENABLED +#include "stm32u5xx_hal_gtzc.h" +#endif /* HAL_GTZC_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED +#include "stm32u5xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED +#include "stm32u5xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DSI_MODULE_ENABLED +#include "stm32u5xx_hal_dsi.h" +#endif /* HAL_DSI_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED +#include "stm32u5xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_PKA_MODULE_ENABLED +#include "stm32u5xx_hal_pka.h" +#endif /* HAL_PKA_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED +#include "stm32u5xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED +#include "stm32u5xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED +#include "stm32u5xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED +#include "stm32u5xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED +#include "stm32u5xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED +#include "stm32u5xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED +#include "stm32u5xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED +#include "stm32u5xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_MMC_MODULE_ENABLED +#include "stm32u5xx_hal_mmc.h" +#endif /* HAL_MMC_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED +#include "stm32u5xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED +#include "stm32u5xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED +#include "stm32u5xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED +#include "stm32u5xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32u5xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED +#include "stm32u5xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32u5xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED +#include "stm32u5xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_OSPI_MODULE_ENABLED +#include "stm32u5xx_hal_ospi.h" +#endif /* HAL_OSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED +#include "stm32u5xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED +#include "stm32u5xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED +#include "stm32u5xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED +#include "stm32u5xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED +#include "stm32u5xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED +#include "stm32u5xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED +#include "stm32u5xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED +#include "stm32u5xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED +#include "stm32u5xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED +#include "stm32u5xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED +#include "stm32u5xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED +#include "stm32u5xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED +#include "stm32u5xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED +#include "stm32u5xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED +#include "stm32u5xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +#ifdef HAL_CORDIC_MODULE_ENABLED +#include "stm32u5xx_hal_cordic.h" +#endif /* HAL_CORDIC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED +#include "stm32u5xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED +#include "stm32u5xx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_FDCAN_MODULE_ENABLED +#include "stm32u5xx_hal_fdcan.h" +#endif /* HAL_FDCAN_MODULE_ENABLED */ + +#ifdef HAL_FMAC_MODULE_ENABLED +#include "stm32u5xx_hal_fmac.h" +#endif /* HAL_FMAC_MODULE_ENABLED */ + +#ifdef HAL_GFXMMU_MODULE_ENABLED +#include "stm32u5xx_hal_gfxmmu.h" +#endif /* HAL_GFXMMU_MODULE_ENABLED */ + +#ifdef HAL_GPU2D_MODULE_ENABLED +#include "stm32u5xx_hal_gpu2d.h" +#endif /* HAL_GPU2D_MODULE_ENABLED */ + +#ifdef HAL_OTFDEC_MODULE_ENABLED +#include "stm32u5xx_hal_otfdec.h" +#endif /* HAL_OTFDEC_MODULE_ENABLED */ + +#ifdef HAL_PSSI_MODULE_ENABLED +#include "stm32u5xx_hal_pssi.h" +#endif /* HAL_PSSI_MODULE_ENABLED */ + +#ifdef HAL_RAMCFG_MODULE_ENABLED +#include "stm32u5xx_hal_ramcfg.h" +#endif /* HAL_RAMCFG_MODULE_ENABLED */ + +#ifdef HAL_MDF_MODULE_ENABLED +#include "stm32u5xx_hal_mdf.h" +#endif /* HAL_MDF_MODULE_ENABLED */ + +#ifdef HAL_XSPI_MODULE_ENABLED +#include "stm32u5xx_hal_xspi.h" +#endif /* HAL_XSPI_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ +#define assert_param(expr) \ + ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ +void assert_failed(uint8_t *file, uint32_t line); +#else +#define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32U5xx_HAL_CONF_H */ diff --git a/core/embed/trezorhal/stm32u5/supervise.c b/core/embed/trezorhal/stm32u5/supervise.c new file mode 120000 index 0000000000..385e9d43ca --- /dev/null +++ b/core/embed/trezorhal/stm32u5/supervise.c @@ -0,0 +1 @@ +../stm32f4/supervise.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/supervise.h b/core/embed/trezorhal/stm32u5/supervise.h new file mode 120000 index 0000000000..f519770f49 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/supervise.h @@ -0,0 +1 @@ +../stm32f4/supervise.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/systemview.h b/core/embed/trezorhal/stm32u5/systemview.h new file mode 120000 index 0000000000..fda5c909e7 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/systemview.h @@ -0,0 +1 @@ +../../firmware/systemview.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/systick.c b/core/embed/trezorhal/stm32u5/systick.c new file mode 120000 index 0000000000..1a5e42f109 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/systick.c @@ -0,0 +1 @@ +../stm32f4/systick.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/systick.h b/core/embed/trezorhal/stm32u5/systick.h new file mode 120000 index 0000000000..1d1261d2cb --- /dev/null +++ b/core/embed/trezorhal/stm32u5/systick.h @@ -0,0 +1 @@ +../stm32f4/systick.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/tamper.c b/core/embed/trezorhal/stm32u5/tamper.c new file mode 100644 index 0000000000..0ae67f9db5 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/tamper.c @@ -0,0 +1,217 @@ +/* + * 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 . + */ + +#include +#include +#include +#include STM32_HAL_H + +// Fixes a typo in CMSIS Device library for STM32U5 +#undef TAMP_CR3_ITAMP7NOER_Msk +#undef TAMP_CR3_ITAMP7NOER +#define TAMP_CR3_ITAMP7NOER_Msk (0x1UL << TAMP_CR3_ITAMP7NOER_Pos) +#define TAMP_CR3_ITAMP7NOER TAMP_CR3_ITAMP7NOER_Msk + +// more flash efficient function than standard HAL +HAL_StatusTypeDef lsi_init(void) { + uint32_t tickstart = 0U; + + FlagStatus pwrclkchanged = RESET; + + /* Update LSI configuration in Backup Domain control register */ + /* Requires to enable write access to Backup Domain of necessary */ + if (__HAL_RCC_PWR_IS_CLK_DISABLED()) { + __HAL_RCC_PWR_CLK_ENABLE(); + pwrclkchanged = SET; + } + + if (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) { + /* Enable write access to Backup domain */ + SET_BIT(PWR->DBPR, PWR_DBPR_DBP); + + /* Wait for Backup domain Write protection disable */ + tickstart = HAL_GetTick(); + + while (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) { + if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) { + /* Restore clock configuration if changed */ + if (pwrclkchanged == SET) { + __HAL_RCC_PWR_CLK_DISABLE(); + } + return HAL_TIMEOUT; + } + } + } + + uint32_t bdcr_temp = RCC->BDCR; + + if (RCC_LSI_DIV1 != (bdcr_temp & RCC_BDCR_LSIPREDIV)) { + if (((bdcr_temp & RCC_BDCR_LSIRDY) == RCC_BDCR_LSIRDY) && + ((bdcr_temp & RCC_BDCR_LSION) != RCC_BDCR_LSION)) { + /* If LSIRDY is set while LSION is not enabled, LSIPREDIV can't be updated + */ + /* The LSIPREDIV cannot be changed if the LSI is used by the IWDG or by + * the RTC */ + /* Restore clock configuration if changed */ + if (pwrclkchanged == SET) { + __HAL_RCC_PWR_CLK_DISABLE(); + } + return HAL_ERROR; + } + + /* Turn off LSI before changing RCC_BDCR_LSIPREDIV */ + if ((bdcr_temp & RCC_BDCR_LSION) == RCC_BDCR_LSION) { + __HAL_RCC_LSI_DISABLE(); + + tickstart = HAL_GetTick(); + + /* Wait till LSI is disabled */ + while (READ_BIT(RCC->BDCR, RCC_BDCR_LSIRDY) != 0U) + ; + } + + /* Set LSI division factor */ + MODIFY_REG(RCC->BDCR, RCC_BDCR_LSIPREDIV, 0); + } + + /* Enable the Internal Low Speed oscillator (LSI) */ + __HAL_RCC_LSI_ENABLE(); + + /* Wait till LSI is ready */ + while (READ_BIT(RCC->BDCR, RCC_BDCR_LSIRDY) == 0U) + ; + + /* Restore clock configuration if changed */ + if (pwrclkchanged == SET) { + __HAL_RCC_PWR_CLK_DISABLE(); + } + return HAL_OK; +} + +void tamper_init(void) { + RCC_PeriphCLKInitTypeDef clk_init_def = {0}; + + // Enable LSI clock + lsi_init(); + + // Select RTC peripheral clock source + clk_init_def.PeriphClockSelection = RCC_PERIPHCLK_RTC; + clk_init_def.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; + HAL_RCCEx_PeriphCLKConfig(&clk_init_def); + + // Enable RTC peripheral (tampers are part of it) + __HAL_RCC_RTC_ENABLE(); + __HAL_RCC_RTCAPB_CLK_ENABLE(); + + // Clear all pending interrupts + // They may be some as RTC/TAMP peripherals resides inside the + // backup voltage domain + TAMP->SCR = TAMP_SCR_CTAMP2F | TAMP_SCR_CITAMP1F | TAMP_SCR_CITAMP2F | + TAMP_SCR_CITAMP3F | TAMP_SCR_CITAMP5F | TAMP_SCR_CITAMP6F | + TAMP_SCR_CITAMP7F | TAMP_SCR_CITAMP8F | TAMP_SCR_CITAMP9F | + TAMP_SCR_CITAMP11F | TAMP_SCR_CITAMP12F | TAMP_SCR_CITAMP13F; + + NVIC_ClearPendingIRQ(TAMP_IRQn); + + // Enable battery and power monitoring (!@# rework it) + RCC->AHB3ENR |= RCC_AHB3ENR_PWREN; + // HAL_PWR_EnableBkUpAccess(); + PWR->BDCR1 |= PWR_BDCR1_MONEN; + // HAL_PWR_DisableBkUpAccess(); + + // Enable all internal tampers (4th and 10th are intentionally skipped) + // We select all of them despite some of them are never triggered + TAMP->CR1 = + TAMP_CR1_ITAMP1E | // backup domain voltage monitoring + TAMP_CR1_ITAMP2E | // temperature monitoring + TAMP_CR1_ITAMP3E | // LSE monitoring (LSECSS) + TAMP_CR1_ITAMP5E | // RTC calendar overflow + TAMP_CR1_ITAMP6E | // JTAG/SWD access when RDP > 0 + TAMP_CR1_ITAMP7E | // ADC4 analog watchdog monitoring 1 + TAMP_CR1_ITAMP8E | // Monotonic counter 1 overflow + TAMP_CR1_ITAMP9E | // Crypto periherals fault (SAES, AES, PKA, TRNG) + TAMP_CR1_ITAMP11E | // IWDG reset when tamper flag is set + TAMP_CR1_ITAMP12E | // ADC4 analog watchdog monitoring 2 + TAMP_CR1_ITAMP13E; // ADC4 analog watchdog monitoring 3 + + // Switch all internal tampers to the "confirmed" mode + // => all secrets all deleted when any tamper event is triggered + TAMP->CR3 = 0; + + // Setup external tampers + // TAMP_IN2 active low, "confirmed" mode + TAMP->CR2 = 0; + // TAMP_CR2_TAMP2TRG; + + // Set external tamper input filter + TAMP->FLTCR = + // TAMP_FLTCR_TAMPPUDIS | // disable pre-charge of TAMP_INx pins + (3 << TAMP_FLTCR_TAMPPRCH_Pos) | // pre-charge 8 RTCCLK cycles + (2 << TAMP_FLTCR_TAMPFLT_Pos) | // activated after 4 same samples + (7 << TAMP_FLTCR_TAMPFREQ_Pos); // sampling period RTCCLK / 256 (128Hz) + + // Enable all interrupts for all internal tampers + TAMP->IER = TAMP_IER_TAMP2IE | TAMP_IER_ITAMP1IE | TAMP_IER_ITAMP2IE | + TAMP_IER_ITAMP3IE | TAMP_IER_ITAMP5IE | TAMP_IER_ITAMP6IE | + TAMP_IER_ITAMP7IE | TAMP_IER_ITAMP8IE | TAMP_IER_ITAMP9IE | + TAMP_IER_ITAMP11IE | TAMP_IER_ITAMP12IE | TAMP_IER_ITAMP13IE; + + // Enable TAMP interrupt at NVIC controller + NVIC_SetPriority(TAMP_IRQn, IRQ_PRI_TAMP); + NVIC_EnableIRQ(TAMP_IRQn); +} + +// Interrupt handle for all tamper events +// It displays an error message +void TAMP_IRQHandler(void) { + const char* reason = "UNKNOWN"; + + uint32_t sr = TAMP->SR; + TAMP->SCR = sr; + + if (sr & TAMP_SR_TAMP1F) { + reason = "INPUT1"; + } else if (sr & TAMP_SR_TAMP2F) { + reason = "INPUT2"; + } else if (sr & TAMP_SR_ITAMP1F) { + reason = "VOLTAGE"; + } else if (sr & TAMP_SR_ITAMP2F) { + reason = "TEMPERATURE"; + } else if (sr & TAMP_SR_ITAMP3F) { + reason = "LSE CLOCK"; + } else if (sr & TAMP_SR_ITAMP5F) { + reason = "RTC OVERFLOW"; + } else if (sr & TAMP_SR_ITAMP6F) { + reason = "SWD ACCESS"; + } else if (sr & TAMP_SR_ITAMP7F) { + reason = "ANALOG WDG1"; + } else if (sr & TAMP_SR_ITAMP8F) { + reason = "MONO COUNTER"; + } else if (sr & TAMP_SR_ITAMP9F) { + reason = "CRYPTO ERROR"; + } else if (sr & TAMP_SR_ITAMP11F) { + reason = "IWDG"; + } else if (sr & TAMP_SR_ITAMP12F) { + reason = "ANALOG WDG2"; + } else if (sr & TAMP_SR_ITAMP13F) { + reason = "ANALOG WDG3"; + } + + error_shutdown("INTERNAL TAMPER", reason); +} diff --git a/core/embed/trezorhal/stm32u5/trustzone.c b/core/embed/trezorhal/stm32u5/trustzone.c new file mode 100644 index 0000000000..01556a3f0b --- /dev/null +++ b/core/embed/trezorhal/stm32u5/trustzone.c @@ -0,0 +1,200 @@ +#include "trustzone.h" + +#ifdef BOARDLOADER + +#include STM32_HAL_H + +void trustzone_init(void) { +#if defined(__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) + +#if defined(SAU_INIT_REGION0) && (SAU_INIT_REGION0 == 1U) + SAU_INIT_REGION(0); +#endif + +#if defined(SAU_INIT_REGION1) && (SAU_INIT_REGION1 == 1U) + SAU_INIT_REGION(1); +#endif + +#if defined(SAU_INIT_REGION2) && (SAU_INIT_REGION2 == 1U) + SAU_INIT_REGION(2); +#endif + +#if defined(SAU_INIT_REGION3) && (SAU_INIT_REGION3 == 1U) + SAU_INIT_REGION(3); +#endif + +#if defined(SAU_INIT_REGION4) && (SAU_INIT_REGION4 == 1U) + SAU_INIT_REGION(4); +#endif + +#if defined(SAU_INIT_REGION5) && (SAU_INIT_REGION5 == 1U) + SAU_INIT_REGION(5); +#endif + +#if defined(SAU_INIT_REGION6) && (SAU_INIT_REGION6 == 1U) + SAU_INIT_REGION(6); +#endif + +#if defined(SAU_INIT_REGION7) && (SAU_INIT_REGION7 == 1U) + SAU_INIT_REGION(7); +#endif + + /* repeat this for all possible SAU regions */ + +#endif /* defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) */ + +#if defined(SAU_INIT_CTRL) && (SAU_INIT_CTRL == 1U) + SAU->CTRL = + ((SAU_INIT_CTRL_ENABLE << SAU_CTRL_ENABLE_Pos) & SAU_CTRL_ENABLE_Msk) | + ((SAU_INIT_CTRL_ALLNS << SAU_CTRL_ALLNS_Pos) & SAU_CTRL_ALLNS_Msk); +#endif + +#if defined(SCB_CSR_AIRCR_INIT) && (SCB_CSR_AIRCR_INIT == 1U) + SCB->SCR = (SCB->SCR & ~(SCB_SCR_SLEEPDEEPS_Msk)) | + ((SCB_CSR_DEEPSLEEPS_VAL << SCB_SCR_SLEEPDEEPS_Pos) & + SCB_SCR_SLEEPDEEPS_Msk); + + SCB->AIRCR = + (SCB->AIRCR & ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_SYSRESETREQS_Msk | + SCB_AIRCR_BFHFNMINS_Msk | SCB_AIRCR_PRIS_Msk)) | + ((0x05FAU << SCB_AIRCR_VECTKEY_Pos) & SCB_AIRCR_VECTKEY_Msk) | + ((SCB_AIRCR_SYSRESETREQS_VAL << SCB_AIRCR_SYSRESETREQS_Pos) & + SCB_AIRCR_SYSRESETREQS_Msk) | + ((SCB_AIRCR_PRIS_VAL << SCB_AIRCR_PRIS_Pos) & SCB_AIRCR_PRIS_Msk) | + ((SCB_AIRCR_BFHFNMINS_VAL << SCB_AIRCR_BFHFNMINS_Pos) & + SCB_AIRCR_BFHFNMINS_Msk); +#endif /* defined (SCB_CSR_AIRCR_INIT) && (SCB_CSR_AIRCR_INIT == 1U) */ + +#if defined(__FPU_USED) && (__FPU_USED == 1U) && defined(TZ_FPU_NS_USAGE) && \ + (TZ_FPU_NS_USAGE == 1U) + + SCB->NSACR = (SCB->NSACR & ~(SCB_NSACR_CP10_Msk | SCB_NSACR_CP11_Msk)) | + ((SCB_NSACR_CP10_11_VAL << SCB_NSACR_CP10_Pos) & + (SCB_NSACR_CP10_Msk | SCB_NSACR_CP11_Msk)); + + FPU->FPCCR = (FPU->FPCCR & ~(FPU_FPCCR_TS_Msk | FPU_FPCCR_CLRONRETS_Msk | + FPU_FPCCR_CLRONRET_Msk)) | + ((FPU_FPCCR_TS_VAL << FPU_FPCCR_TS_Pos) & FPU_FPCCR_TS_Msk) | + ((FPU_FPCCR_CLRONRETS_VAL << FPU_FPCCR_CLRONRETS_Pos) & + FPU_FPCCR_CLRONRETS_Msk) | + ((FPU_FPCCR_CLRONRET_VAL << FPU_FPCCR_CLRONRET_Pos) & + FPU_FPCCR_CLRONRET_Msk); +#endif + +#if defined(NVIC_INIT_ITNS0) && (NVIC_INIT_ITNS0 == 1U) + NVIC->ITNS[0] = NVIC_INIT_ITNS0_VAL; +#endif + +#if defined(NVIC_INIT_ITNS1) && (NVIC_INIT_ITNS1 == 1U) + NVIC->ITNS[1] = NVIC_INIT_ITNS1_VAL; +#endif + +#if defined(NVIC_INIT_ITNS2) && (NVIC_INIT_ITNS2 == 1U) + NVIC->ITNS[2] = NVIC_INIT_ITNS2_VAL; +#endif + +#if defined(NVIC_INIT_ITNS3) && (NVIC_INIT_ITNS3 == 1U) + NVIC->ITNS[3] = NVIC_INIT_ITNS3_VAL; +#endif + +#if defined(NVIC_INIT_ITNS4) && (NVIC_INIT_ITNS4 == 1U) + NVIC->ITNS[4] = NVIC_INIT_ITNS4_VAL; +#endif +} + +void trustzone_run(void) { + uint32_t index; + MPCBB_ConfigTypeDef MPCBB_desc; + + /* Enable GTZC peripheral clock */ + __HAL_RCC_GTZC1_CLK_ENABLE(); + __HAL_RCC_GTZC2_CLK_ENABLE(); + + /* -------------------------------------------------------------------------*/ + /* Memory isolation configuration */ + /* Initializes the memory that secure application books for non secure */ + /* -------------------------------------------------------------------------*/ + + /* -------------------------------------------------------------------------*/ + /* Internal RAM : */ + /* The booking is done through GTZC MPCBB. */ + /* Internal SRAMs are secured by default and configured by block */ + /* of 512 bytes. */ + + MPCBB_desc.SecureRWIllegalMode = GTZC_MPCBB_SRWILADIS_DISABLE; + MPCBB_desc.InvertSecureState = GTZC_MPCBB_INVSECSTATE_NOT_INVERTED; + MPCBB_desc.AttributeConfig.MPCBB_LockConfig_array[0] = + 0x00000000U; /* Unlocked configuration */ + + for (index = 0; index < 52; index++) { + MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[index] = 0xFFFFFFFFU; + MPCBB_desc.AttributeConfig.MPCBB_PrivConfig_array[index] = 0x00000000U; + } + + HAL_GTZC_MPCBB_ConfigMem(SRAM1_BASE, &MPCBB_desc); + HAL_GTZC_MPCBB_ConfigMem(SRAM2_BASE, &MPCBB_desc); + HAL_GTZC_MPCBB_ConfigMem(SRAM3_BASE, &MPCBB_desc); + HAL_GTZC_MPCBB_ConfigMem(SRAM4_BASE, &MPCBB_desc); +#if defined STM32U5A9xx | defined STM32U5G9xx + HAL_GTZC_MPCBB_ConfigMem(SRAM5_BASE, &MPCBB_desc); +#endif +#if defined STM32U5G9xx + HAL_GTZC_MPCBB_ConfigMem(SRAM6_BASE, &MPCBB_desc); +#endif + + /* -------------------------------------------------------------------------*/ + /* Internal Flash */ + /* The booking is done in both IDAU/SAU and FLASH interface */ + + /* Flash memory is secured by default and modified with Option Byte Loading */ + /* Insure SECWM2_PSTRT > SECWM2_PEND in order to have all Bank2 non-secure */ + + /* -------------------------------------------------------------------------*/ + /* External OctoSPI memory */ + /* The booking is done in both IDAU/SAU and GTZC MPCWM interface */ + + /* Default secure configuration */ + /* Else need to use HAL_GTZC_TZSC_MPCWM_ConfigMemAttributes() */ + + /* -------------------------------------------------------------------------*/ + /* External NOR/FMC memory */ + /* The booking is done in both IDAU/SAU and GTZC MPCWM interface */ + + /* Default secure configuration */ + /* Else need to use HAL_GTZC_TZSC_MPCWM_ConfigMemAttributes() */ + + /* -------------------------------------------------------------------------*/ + /* External NAND/FMC memory */ + /* The booking is done in both IDAU/SAU and GTZC MPCWM interface */ + + /* Default secure configuration */ + /* Else need to use HAL_GTZC_TZSC_MPCWM_ConfigMemAttributes() */ + + /* -------------------------------------------------------------------------*/ + /* Peripheral isolation configuration */ + /* Initializes the peripherals and features that secure application books */ + /* for secure (RCC, PWR, RTC, EXTI, DMA, OTFDEC, etc..) or leave them to */ + /* non-secure (GPIO (secured by default)) */ + /* -------------------------------------------------------------------------*/ + +#if defined STM32U5A9xx | defined STM32U5G9xx + HAL_GTZC_TZSC_ConfigPeriphAttributes(GTZC_PERIPH_LTDC, GTZC_TZSC_PERIPH_SEC); + HAL_GTZC_TZSC_ConfigPeriphAttributes(GTZC_PERIPH_DSI, GTZC_TZSC_PERIPH_SEC); + HAL_GTZC_TZSC_ConfigPeriphAttributes(GTZC_PERIPH_GFXMMU, + GTZC_TZSC_PERIPH_SEC); + HAL_GTZC_TZSC_ConfigPeriphAttributes(GTZC_PERIPH_GFXMMU_REG, + GTZC_TZSC_PERIPH_SEC); +#endif + HAL_GTZC_TZSC_ConfigPeriphAttributes(GTZC_PERIPH_DMA2D, GTZC_TZSC_PERIPH_SEC); + + /* Clear all illegal access flags in GTZC TZIC */ + HAL_GTZC_TZIC_ClearFlag(GTZC_PERIPH_ALL); + + /* Enable all illegal access interrupts in GTZC TZIC */ + HAL_GTZC_TZIC_EnableIT(GTZC_PERIPH_ALL); + + /* Enable GTZC secure interrupt */ + HAL_NVIC_SetPriority(GTZC_IRQn, 0, 0); /* Highest priority level */ + HAL_NVIC_EnableIRQ(GTZC_IRQn); +} +#endif diff --git a/core/embed/trezorhal/stm32u5/usb.c b/core/embed/trezorhal/stm32u5/usb.c new file mode 120000 index 0000000000..e05e3c0912 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usb.c @@ -0,0 +1 @@ +../stm32f4/usb.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usb_hid-impl.h b/core/embed/trezorhal/stm32u5/usb_hid-impl.h new file mode 120000 index 0000000000..89e47b5ef0 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usb_hid-impl.h @@ -0,0 +1 @@ +../stm32f4/usb_hid-impl.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usb_vcp-impl.h b/core/embed/trezorhal/stm32u5/usb_vcp-impl.h new file mode 120000 index 0000000000..be4e3b8e74 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usb_vcp-impl.h @@ -0,0 +1 @@ +../stm32f4/usb_vcp-impl.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usb_webusb-impl.h b/core/embed/trezorhal/stm32u5/usb_webusb-impl.h new file mode 120000 index 0000000000..749c2f52f9 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usb_webusb-impl.h @@ -0,0 +1 @@ +../stm32f4/usb_webusb-impl.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_conf.c b/core/embed/trezorhal/stm32u5/usbd_conf.c new file mode 120000 index 0000000000..96c576f982 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_conf.c @@ -0,0 +1 @@ +../stm32f4/usbd_conf.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_conf.h b/core/embed/trezorhal/stm32u5/usbd_conf.h new file mode 120000 index 0000000000..21f3e5266e --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_conf.h @@ -0,0 +1 @@ +../stm32f4/usbd_conf.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_core.c b/core/embed/trezorhal/stm32u5/usbd_core.c new file mode 120000 index 0000000000..554c29cbfa --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_core.c @@ -0,0 +1 @@ +../stm32f4/usbd_core.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_core.h b/core/embed/trezorhal/stm32u5/usbd_core.h new file mode 120000 index 0000000000..ee7585f5a3 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_core.h @@ -0,0 +1 @@ +../stm32f4/usbd_core.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_ctlreq.c b/core/embed/trezorhal/stm32u5/usbd_ctlreq.c new file mode 120000 index 0000000000..a9065b0abe --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_ctlreq.c @@ -0,0 +1 @@ +../stm32f4/usbd_ctlreq.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_ctlreq.h b/core/embed/trezorhal/stm32u5/usbd_ctlreq.h new file mode 120000 index 0000000000..8f764f56a9 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_ctlreq.h @@ -0,0 +1 @@ +../stm32f4/usbd_ctlreq.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_def.h b/core/embed/trezorhal/stm32u5/usbd_def.h new file mode 120000 index 0000000000..72e5b4b70f --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_def.h @@ -0,0 +1 @@ +../stm32f4/usbd_def.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_ioreq.c b/core/embed/trezorhal/stm32u5/usbd_ioreq.c new file mode 120000 index 0000000000..cf5c0a30e2 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_ioreq.c @@ -0,0 +1 @@ +../stm32f4/usbd_ioreq.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_ioreq.h b/core/embed/trezorhal/stm32u5/usbd_ioreq.h new file mode 120000 index 0000000000..06da29b5c6 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_ioreq.h @@ -0,0 +1 @@ +../stm32f4/usbd_ioreq.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/util.s b/core/embed/trezorhal/stm32u5/util.s new file mode 100644 index 0000000000..be2eff48bf --- /dev/null +++ b/core/embed/trezorhal/stm32u5/util.s @@ -0,0 +1,205 @@ + .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! + cmp r0, r1 + beq .L_loop_end + .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 + .L_loop_end: + bx lr + + // Jump to address given in first argument R0 that points to next's stage's VTOR + // Clear memory and all registers before jump + .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 + 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, =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, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + mov lr, r4 + // clear out the general purpose registers before the next stage's except the register with flag R11 + 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 + 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, =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, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + 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, =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, =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, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =1 + msr control, r0 // jump to unprivileged mode + ldr r0, =0 + b . // loop forever + + .end diff --git a/core/embed/trezorhal/stm32u5/vectortable.s b/core/embed/trezorhal/stm32u5/vectortable.s new file mode 100644 index 0000000000..2a9e9cb653 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/vectortable.s @@ -0,0 +1,177 @@ + .syntax unified + + .text + + .global default_handler + .type default_handler, STT_FUNC +default_handler: + b shutdown_privileged + + .macro add_handler symbol_name:req + .word \symbol_name + .weak \symbol_name + .thumb_set \symbol_name, default_handler + .endm + + // Reference: + // Table 62 - STM32F427 Reference manual (RM0090) + // Section B1.5 - ARMv7-M Architecture Reference Manual + .section .vector_table, "a" +vector_table: + .word main_stack_base // defined in linker script + add_handler reset_handler + add_handler NMI_Handler + add_handler HardFault_Handler + add_handler MemManage_Handler + add_handler BusFault_Handler + add_handler UsageFault_Handler + add_handler SecureFault_Handler + add_handler architecture_reserved_handler + add_handler architecture_reserved_handler + add_handler architecture_reserved_handler + add_handler SVC_Handler + add_handler DebugMon_Handler + add_handler architecture_reserved_handler + add_handler PendSV_Handler + add_handler SysTick_Handler + add_handler WWDG_IRQHandler + add_handler PVD_PVM_IRQHandler + add_handler RTC_IRQHandler + add_handler RTC_S_IRQHandler + add_handler TAMP_IRQHandler + add_handler RAMCFG_IRQHandler + add_handler FLASH_IRQHandler + add_handler FLASH_S_IRQHandler + add_handler GTZC_IRQHandler + add_handler RCC_IRQHandler + add_handler RCC_S_IRQHandler + add_handler EXTI0_IRQHandler + add_handler EXTI1_IRQHandler + add_handler EXTI2_IRQHandler + add_handler EXTI3_IRQHandler + add_handler EXTI4_IRQHandler + add_handler EXTI5_IRQHandler + add_handler EXTI6_IRQHandler + add_handler EXTI7_IRQHandler + add_handler EXTI8_IRQHandler + add_handler EXTI9_IRQHandler + add_handler EXTI10_IRQHandler + add_handler EXTI11_IRQHandler + add_handler EXTI12_IRQHandler + add_handler EXTI13_IRQHandler + add_handler EXTI14_IRQHandler + add_handler EXTI15_IRQHandler + add_handler IWDG_IRQHandler + add_handler SAES_IRQHandler + add_handler GPDMA1_Channel0_IRQHandler + add_handler GPDMA1_Channel1_IRQHandler + add_handler GPDMA1_Channel2_IRQHandler + add_handler GPDMA1_Channel3_IRQHandler + add_handler GPDMA1_Channel4_IRQHandler + add_handler GPDMA1_Channel5_IRQHandler + add_handler GPDMA1_Channel6_IRQHandler + add_handler GPDMA1_Channel7_IRQHandler + add_handler ADC1_2_IRQHandler + add_handler DAC1_IRQHandler + add_handler FDCAN1_IT0_IRQHandler + add_handler FDCAN1_IT1_IRQHandler + add_handler TIM1_BRK_IRQHandler + add_handler TIM1_UP_IRQHandler + add_handler TIM1_TRG_COM_IRQHandler + add_handler TIM1_CC_IRQHandler + add_handler TIM2_IRQHandler + add_handler TIM3_IRQHandler + add_handler TIM4_IRQHandler + add_handler TIM5_IRQHandler + add_handler TIM6_IRQHandler + add_handler TIM7_IRQHandler + add_handler TIM8_BRK_IRQHandler + add_handler TIM8_UP_IRQHandler + add_handler TIM8_TRG_COM_IRQHandler + add_handler TIM8_CC_IRQHandler + add_handler I2C1_EV_IRQHandler + add_handler I2C1_ER_IRQHandler + add_handler I2C2_EV_IRQHandler + add_handler I2C2_ER_IRQHandler + add_handler SPI1_IRQHandler + add_handler SPI2_IRQHandler + add_handler USART1_IRQHandler + add_handler USART2_IRQHandler + add_handler USART3_IRQHandler + add_handler UART4_IRQHandler + add_handler UART5_IRQHandler + add_handler LPUART1_IRQHandler + add_handler LPTIM1_IRQHandler + add_handler LPTIM2_IRQHandler + add_handler TIM15_IRQHandler + add_handler TIM16_IRQHandler + add_handler TIM17_IRQHandler + add_handler COMP_IRQHandler + add_handler OTG_HS_IRQHandler + add_handler CRS_IRQHandler + add_handler FMC_IRQHandler + add_handler OCTOSPI1_IRQHandler + add_handler PWR_S3WU_IRQHandler + add_handler SDMMC1_IRQHandler + add_handler SDMMC2_IRQHandler + add_handler GPDMA1_Channel8_IRQHandler + add_handler GPDMA1_Channel9_IRQHandler + add_handler GPDMA1_Channel10_IRQHandler + add_handler GPDMA1_Channel11_IRQHandler + add_handler GPDMA1_Channel12_IRQHandler + add_handler GPDMA1_Channel13_IRQHandler + add_handler GPDMA1_Channel14_IRQHandler + add_handler GPDMA1_Channel15_IRQHandler + add_handler I2C3_EV_IRQHandler + add_handler I2C3_ER_IRQHandler + add_handler SAI1_IRQHandler + add_handler SAI2_IRQHandler + add_handler TSC_IRQHandler + add_handler AES_IRQHandler + add_handler RNG_IRQHandler + add_handler FPU_IRQHandler + add_handler HASH_IRQHandler + add_handler PKA_IRQHandler + add_handler LPTIM3_IRQHandler + add_handler SPI3_IRQHandler + add_handler I2C4_ER_IRQHandler + add_handler I2C4_EV_IRQHandler + add_handler MDF1_FLT0_IRQHandler + add_handler MDF1_FLT1_IRQHandler + add_handler MDF1_FLT2_IRQHandler + add_handler MDF1_FLT3_IRQHandler + add_handler UCPD1_IRQHandler + add_handler ICACHE_IRQHandler + add_handler OTFDEC1_IRQHandler + add_handler OTFDEC2_IRQHandler + add_handler LPTIM4_IRQHandler + add_handler DCACHE1_IRQHandler + add_handler ADF1_IRQHandler + add_handler ADC4_IRQHandler + add_handler LPDMA1_Channel0_IRQHandler + add_handler LPDMA1_Channel1_IRQHandler + add_handler LPDMA1_Channel2_IRQHandler + add_handler LPDMA1_Channel3_IRQHandler + add_handler DMA2D_IRQHandler + add_handler DCMI_PSSI_IRQHandler + add_handler OCTOSPI2_IRQHandler + add_handler MDF1_FLT4_IRQHandler + add_handler MDF1_FLT5_IRQHandler + add_handler CORDIC_IRQHandler + add_handler FMAC_IRQHandler + add_handler LSECSSD_IRQHandler + add_handler USART6_IRQHandler + add_handler I2C5_ER_IRQHandler + add_handler I2C5_EV_IRQHandler + add_handler I2C6_ER_IRQHandler + add_handler I2C6_EV_IRQHandler + add_handler HSPI1_IRQHandler + add_handler GPU2D_IRQHandler + add_handler GPU2D_ER_IRQHandler + add_handler GFXMMU_IRQHandler + add_handler LTDC_IRQHandler + add_handler LTDC_ER_IRQHandler + add_handler DSI_IRQHandler + add_handler DCACHE2_IRQHandler + + .end diff --git a/core/embed/trezorhal/tamper.h b/core/embed/trezorhal/tamper.h new file mode 100644 index 0000000000..5d3fe12b09 --- /dev/null +++ b/core/embed/trezorhal/tamper.h @@ -0,0 +1,38 @@ +/* + * 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 . + */ + +#ifndef TREZOR_HAL_TAMPER_H +#define TREZOR_HAL_TAMPER_H + +#include + +// Tamper module enables the internal tamper detection on STM32 microcontroller +// as well as external tamper input if it's available on the device + +// Initializes the tamper detection +void tamper_init(void); + +// Triggers one of internal tampers. +// The function is intended for experimentation with internal tamper mechanism +// Use TAMP_CR1_xxx constants to as a parameter +// Only TAMP_CR1_ITAMP5E (RTC) and TAMP_CR1_ITAMP8E (monotonic counter) +// are supported +void tamper_test(uint32_t tamper_type); + +#endif // TREZOR_HAL_TAMPER_H diff --git a/core/embed/trezorhal/trustzone.h b/core/embed/trezorhal/trustzone.h new file mode 100644 index 0000000000..b0ceaeb2e3 --- /dev/null +++ b/core/embed/trezorhal/trustzone.h @@ -0,0 +1,574 @@ +#ifndef __TREZORHAL_TRUSTZONE__ +#define __TREZORHAL_TRUSTZONE__ + +#ifdef BOARDLOADER +#define CMSE_NS_CALL __attribute((cmse_nonsecure_call)) +#define CMSE_NS_ENTRY __attribute((cmse_nonsecure_entry)) + +typedef void CMSE_NS_CALL (*funcptr)(void); + +/* typedef for non-secure callback functions */ +typedef funcptr funcptr_NS; + +#include STM32_HAL_H + +/* +//-------- <<< Use Configuration Wizard in Context Menu >>> ----------------- +*/ + +/* +// Initialize Security Attribution Unit (SAU) CTRL register +*/ +#define SAU_INIT_CTRL 1 + +/* +// Enable SAU +// Value for SAU->CTRL register bit ENABLE +*/ +#define SAU_INIT_CTRL_ENABLE 0 + +/* +// When SAU is disabled +// <0=> All Memory is Secure +// <1=> All Memory is Non-Secure +// Value for SAU->CTRL register bit ALLNS +// When all Memory is Non-Secure (ALLNS is 1), IDAU can override memory +map configuration. +*/ +#define SAU_INIT_CTRL_ALLNS 1 + +/* +// +*/ + +/* +// Initialize Security Attribution Unit (SAU) Address Regions +// SAU configuration specifies regions to be one of: +// - Secure and Non-Secure Callable +// - Non-Secure +// Note: All memory regions not configured by SAU are Secure +*/ +#define SAU_REGIONS_MAX 8 /* Max. number of SAU regions */ + +/* +// Initialize SAU Region 0 +// Setup SAU Region 0 memory attributes +*/ +#define SAU_INIT_REGION0 0 + +/* +// Start Address <0-0xFFFFFFE0> +*/ +#define SAU_INIT_START0 0x0C1FE000 /* start address of SAU region 0 */ + +/* +// End Address <0x1F-0xFFFFFFFF> +*/ +#define SAU_INIT_END0 0x0C1FFFFF /* end address of SAU region 0 */ + +/* +// Region is +// <0=>Non-Secure +// <1=>Secure, Non-Secure Callable +*/ +#define SAU_INIT_NSC0 1 +/* +// +*/ + +/* +// Initialize SAU Region 1 +// Setup SAU Region 1 memory attributes +*/ +#define SAU_INIT_REGION1 0 + +/* +// Start Address <0-0xFFFFFFE0> +*/ +#define SAU_INIT_START1 0x08200000 /* start address of SAU region 1 */ + +/* +// End Address <0x1F-0xFFFFFFFF> +*/ +#define SAU_INIT_END1 0x083FFFFF /* end address of SAU region 1 */ + +/* +// Region is +// <0=>Non-Secure +// <1=>Secure, Non-Secure Callable +*/ +#define SAU_INIT_NSC1 0 +/* +// +*/ + +/* +// Initialize SAU Region 2 +// Setup SAU Region 2 memory attributes +*/ +#define SAU_INIT_REGION2 0 + +/* +// Start Address <0-0xFFFFFFE0> +*/ +#define SAU_INIT_START2 0x200D0000 /* start address of SAU region 2 */ + +/* +// End Address <0x1F-0xFFFFFFFF> +*/ +#define SAU_INIT_END2 0x2026FFFF /* end address of SAU region 2 */ + +/* +// Region is +// <0=>Non-Secure +// <1=>Secure, Non-Secure Callable +*/ +#define SAU_INIT_NSC2 0 +/* +// +*/ + +/* +// Initialize SAU Region 3 +// Setup SAU Region 3 memory attributes +*/ +#define SAU_INIT_REGION3 0 + +/* +// Start Address <0-0xFFFFFFE0> +*/ +#define SAU_INIT_START3 0x40000000 /* start address of SAU region 3 */ + +/* +// End Address <0x1F-0xFFFFFFFF> +*/ +#define SAU_INIT_END3 0x4FFFFFFF /* end address of SAU region 3 */ + +/* +// Region is +// <0=>Non-Secure +// <1=>Secure, Non-Secure Callable +*/ +#define SAU_INIT_NSC3 0 +/* +// +*/ + +/* +// Initialize SAU Region 4 +// Setup SAU Region 4 memory attributes +*/ +#define SAU_INIT_REGION4 0 + +/* +// Start Address <0-0xFFFFFFE0> +*/ +#define SAU_INIT_START4 0x60000000 /* start address of SAU region 4 */ + +/* +// End Address <0x1F-0xFFFFFFFF> +*/ +#define SAU_INIT_END4 0xAFFFFFFF /* end address of SAU region 4 */ + +/* +// Region is +// <0=>Non-Secure +// <1=>Secure, Non-Secure Callable +*/ +#define SAU_INIT_NSC4 0 +/* +// +*/ + +/* +// Initialize SAU Region 5 +// Setup SAU Region 5 memory attributes +*/ +#define SAU_INIT_REGION5 0 + +/* +// Start Address <0-0xFFFFFFE0> +*/ +#define SAU_INIT_START5 0x0BF90000 /* start address of SAU region 5 */ + +/* +// End Address <0x1F-0xFFFFFFFF> +*/ +#define SAU_INIT_END5 0x0BFA8FFF /* end address of SAU region 5 */ + +/* +// Region is +// <0=>Non-Secure +// <1=>Secure, Non-Secure Callable +*/ +#define SAU_INIT_NSC5 0 +/* +// +*/ + +/* +// Initialize SAU Region 6 +// Setup SAU Region 6 memory attributes +*/ +#define SAU_INIT_REGION6 0 + +/* +// Start Address <0-0xFFFFFFE0> +*/ +#define SAU_INIT_START6 0x00000000 /* start address of SAU region 6 */ + +/* +// End Address <0x1F-0xFFFFFFFF> +*/ +#define SAU_INIT_END6 0x00000000 /* end address of SAU region 6 */ + +/* +// Region is +// <0=>Non-Secure +// <1=>Secure, Non-Secure Callable +*/ +#define SAU_INIT_NSC6 0 +/* +// +*/ + +/* +// Initialize SAU Region 7 +// Setup SAU Region 7 memory attributes +*/ +#define SAU_INIT_REGION7 0 + +/* +// Start Address <0-0xFFFFFFE0> +*/ +#define SAU_INIT_START7 0x00000000 /* start address of SAU region 7 */ + +/* +// End Address <0x1F-0xFFFFFFFF> +*/ +#define SAU_INIT_END7 0x00000000 /* end address of SAU region 7 */ + +/* +// Region is +// <0=>Non-Secure +// <1=>Secure, Non-Secure Callable +*/ +#define SAU_INIT_NSC7 0 +/* +// +*/ + +/* +// +*/ + +/* +// Setup behaviour of Sleep and Exception Handling +*/ +#define SCB_CSR_AIRCR_INIT 0 + +/* +// Deep Sleep can be enabled by +// <0=>Secure and Non-Secure state +// <1=>Secure state only +// Value for SCB->CSR register bit DEEPSLEEPS +*/ +#define SCB_CSR_DEEPSLEEPS_VAL 0 + +/* +// System reset request accessible from +// <0=> Secure and Non-Secure state +// <1=> Secure state only +// Value for SCB->AIRCR register bit SYSRESETREQS +*/ +#define SCB_AIRCR_SYSRESETREQS_VAL 0 + +/* +// Priority of Non-Secure exceptions is +// <0=> Not altered +// <1=> Lowered to 0x04-0x07 +// Value for SCB->AIRCR register bit PRIS +*/ +#define SCB_AIRCR_PRIS_VAL 0 + +/* +// BusFault, HardFault, and NMI target +// <0=> Secure state +// <1=> Non-Secure state +// Value for SCB->AIRCR register bit BFHFNMINS +*/ +#define SCB_AIRCR_BFHFNMINS_VAL 0 + +/* +// +*/ + +/* +// Setup behaviour of Floating Point Unit +*/ +#define TZ_FPU_NS_USAGE 1 + +/* +// Floating Point Unit usage +// <0=> Secure state only +// <3=> Secure and Non-Secure state +// Value for SCB->NSACR register bits CP10, CP11 +*/ +#define SCB_NSACR_CP10_11_VAL 3 + +/* +// Treat floating-point registers as Secure +// <0=> Disabled +// <1=> Enabled +// Value for FPU->FPCCR register bit TS +*/ +#define FPU_FPCCR_TS_VAL 0 + +/* +// Clear on return (CLRONRET) accessibility +// <0=> Secure and Non-Secure state +// <1=> Secure state only +// Value for FPU->FPCCR register bit CLRONRETS +*/ +#define FPU_FPCCR_CLRONRETS_VAL 0 + +/* +// Clear floating-point caller saved registers on exception return +// <0=> Disabled +// <1=> Enabled +// Value for FPU->FPCCR register bit CLRONRET +*/ +#define FPU_FPCCR_CLRONRET_VAL 1 + +/* +// +*/ + +/* +// Setup Interrupt Target +*/ + +/* +// Initialize ITNS 0 (Interrupts 0..31) +*/ +#define NVIC_INIT_ITNS0 1 + +/* +// Interrupts 0..31 +// WWDG_IRQn <0=> Secure state <1=> Non-Secure state +// PVD_PVM_IRQn <0=> Secure state <1=> Non-Secure state +// RTC_IRQn <0=> Secure state <1=> Non-Secure state +// RTC_S_IRQn <0=> Secure state <1=> Non-Secure state +// TAMP_IRQn <0=> Secure state <1=> Non-Secure state +// RAMCFG_IRQn <0=> Secure state <1=> Non-Secure state +// FLASH_IRQn <0=> Secure state <1=> Non-Secure state +// FLASH_S_IRQn <0=> Secure state <1=> Non-Secure state +// GTZC_IRQn <0=> Secure state <1=> Non-Secure state +// RCC_IRQn <0=> Secure state <1=> Non-Secure state +// RCC_S_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI0_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI1_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI2_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI3_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI4_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI5_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI6_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI7_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI8_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI9_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI10_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI11_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI12_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI13_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI14_IRQn <0=> Secure state <1=> Non-Secure state +// EXTI15_IRQn <0=> Secure state <1=> Non-Secure state +// IWDG_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel0_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel1_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel2_IRQn <0=> Secure state <1=> Non-Secure state +*/ +#define NVIC_INIT_ITNS0_VAL 0x00000000 + +/* +// +*/ + +/* +// Initialize ITNS 1 (Interrupts 32..63) +*/ +#define NVIC_INIT_ITNS1 1 + +/* +// Interrupts 32..63 +// GPDMA1_Channel3_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel4_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel5_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel6_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel7_IRQn <0=> Secure state <1=> Non-Secure state +// ADC1_IRQn <0=> Secure state <1=> Non-Secure state +// DAC1_IRQn <0=> Secure state <1=> Non-Secure state +// FDCAN1_IT0_IRQn <0=> Secure state <1=> Non-Secure state +// FDCAN1_IT1_IRQn <0=> Secure state <1=> Non-Secure state +// TIM1_BRK_IRQn <0=> Secure state <1=> Non-Secure state +// TIM1_UP_IRQn <0=> Secure state <1=> Non-Secure state +// TIM1_TRG_COM_IRQn <0=> Secure state <1=> Non-Secure state +// TIM1_CC_IRQn <0=> Secure state <1=> Non-Secure state +// TIM2_IRQn <0=> Secure state <1=> Non-Secure state +// TIM3_IRQn <0=> Secure state <1=> Non-Secure state +// TIM4_IRQn <0=> Secure state <1=> Non-Secure state +// TIM5_IRQn <0=> Secure state <1=> Non-Secure state +// TIM6_IRQn <0=> Secure state <1=> Non-Secure state +// TIM7_IRQn <0=> Secure state <1=> Non-Secure state +// TIM8_BRK_IRQn <0=> Secure state <1=> Non-Secure state +// TIM8_UP_IRQn <0=> Secure state <1=> Non-Secure state +// TIM8_TRG_COM_IRQn <0=> Secure state <1=> Non-Secure state +// TIM8_CC_IRQn <0=> Secure state <1=> Non-Secure state +// I2C1_EV_IRQn <0=> Secure state <1=> Non-Secure state +// I2C1_ER_IRQn <0=> Secure state <1=> Non-Secure state +// I2C2_EV_IRQn <0=> Secure state <1=> Non-Secure state +// I2C2_ER_IRQn <0=> Secure state <1=> Non-Secure state +// SPI1_IRQn <0=> Secure state <1=> Non-Secure state +// SPI2_IRQn <0=> Secure state <1=> Non-Secure state +// USART1_IRQn <0=> Secure state <1=> Non-Secure state +// USART2_IRQn <0=> Secure state <1=> Non-Secure state +// USART3_IRQn <0=> Secure state <1=> Non-Secure state +*/ +#define NVIC_INIT_ITNS1_VAL 0x00000000 + +/* +// +*/ + +/* +// Initialize ITNS 2 (Interrupts 64..95) +*/ +#define NVIC_INIT_ITNS2 1 + +/* +// Interrupts 64..95 +// UART4_IRQn <0=> Secure state <1=> Non-Secure state +// UART5_IRQn <0=> Secure state <1=> Non-Secure state +// LPUART1_IRQn <0=> Secure state <1=> Non-Secure state +// LPTIM1_IRQn <0=> Secure state <1=> Non-Secure state +// LPTIM2_IRQn <0=> Secure state <1=> Non-Secure state +// TIM15_IRQn <0=> Secure state <1=> Non-Secure state +// TIM16_IRQn <0=> Secure state <1=> Non-Secure state +// TIM17_IRQn <0=> Secure state <1=> Non-Secure state +// COMP_IRQn <0=> Secure state <1=> Non-Secure state +// OTG_HS_IRQn <0=> Secure state <1=> Non-Secure state +// CRS_IRQn <0=> Secure state <1=> Non-Secure state +// FMC_IRQn <0=> Secure state <1=> Non-Secure state +// OCTOSPI1_IRQn <0=> Secure state <1=> Non-Secure state +// PWR_S3WU_IRQn <0=> Secure state <1=> Non-Secure state +// SDMMC1_IRQn <0=> Secure state <1=> Non-Secure state +// SDMMC2_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel8_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel9_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel10_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel11_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel12_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel13_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel14_IRQn <0=> Secure state <1=> Non-Secure state +// GPDMA1_Channel15_IRQn <0=> Secure state <1=> Non-Secure state +// I2C3_EV_IRQn <0=> Secure state <1=> Non-Secure state +// I2C3_ER_IRQn <0=> Secure state <1=> Non-Secure state +// SAI1_IRQn <0=> Secure state <1=> Non-Secure state +// SAI2_IRQn <0=> Secure state <1=> Non-Secure state +// TSC_IRQn <0=> Secure state <1=> Non-Secure state +// RNG_IRQn <0=> Secure state <1=> Non-Secure state +// FPU_IRQn <0=> Secure state <1=> Non-Secure state +*/ +#define NVIC_INIT_ITNS2_VAL 0x00000000 + +/* +// +*/ + +/* +// Initialize ITNS 3 (Interrupts 96..127) +*/ +#define NVIC_INIT_ITNS3 1 + +/* +// Interrupts 96..127 +// HASH_IRQn <0=> Secure state <1=> Non-Secure state +// LPTIM3_IRQn <0=> Secure state <1=> Non-Secure state +// SPI3_IRQn <0=> Secure state <1=> Non-Secure state +// I2C4_ER_IRQn <0=> Secure state <1=> Non-Secure state +// I2C4_EV_IRQn <0=> Secure state <1=> Non-Secure state +// MDF1_FLT0_IRQn <0=> Secure state <1=> Non-Secure state +// MDF1_FLT1_IRQn <0=> Secure state <1=> Non-Secure state +// MDF1_FLT2_IRQn <0=> Secure state <1=> Non-Secure state +// MDF1_FLT3_IRQn <0=> Secure state <1=> Non-Secure state +// UCPD1_IRQn <0=> Secure state <1=> Non-Secure state +// ICACHE_IRQn <0=> Secure state <1=> Non-Secure state +// LPTIM4_IRQn <0=> Secure state <1=> Non-Secure state +// DCACHE1_IRQn <0=> Secure state <1=> Non-Secure state +// ADF1_IRQn <0=> Secure state <1=> Non-Secure state +// ADC4_IRQn <0=> Secure state <1=> Non-Secure state +// LPDMA1_Channel0_IRQn <0=> Secure state <1=> Non-Secure state +// LPDMA1_Channel1_IRQn <0=> Secure state <1=> Non-Secure state +// LPDMA1_Channel2_IRQn <0=> Secure state <1=> Non-Secure state +// LPDMA1_Channel3_IRQn <0=> Secure state <1=> Non-Secure state +// DMA2D_IRQn <0=> Secure state <1=> Non-Secure state +// DCMI_PSSI_IRQn <0=> Secure state <1=> Non-Secure state +// OCTOSPI2_IRQn <0=> Secure state <1=> Non-Secure state +// MDF1_FLT4_IRQn <0=> Secure state <1=> Non-Secure state +// MDF1_FLT5_IRQn <0=> Secure state <1=> Non-Secure state +// CORDIC_IRQn <0=> Secure state <1=> Non-Secure state +// FMAC_IRQn <0=> Secure state <1=> Non-Secure state +// USART6_IRQn <0=> Secure state <1=> Non-Secure state +// I2C5_ER_IRQn <0=> Secure state <1=> Non-Secure state +*/ +#define NVIC_INIT_ITNS3_VAL 0x00000000 + +/* +// +*/ + +/* +// Initialize ITNS 4 (Interrupts 109..138) +*/ +#define NVIC_INIT_ITNS4 1 + +/* +// Interrupts 96..138 +// I2C5_EV_IRQn <0=> Secure state <1=> Non-Secure state +// I2C6_ER_IRQn <0=> Secure state <1=> Non-Secure state +// I2C6_EV_IRQn <0=> Secure state <1=> Non-Secure state +// HSPI1_IRQn <0=> Secure state <1=> Non-Secure state +// GPU2D_IRQn <0=> Secure state <1=> Non-Secure state +// GPU2D_ER_IRQn <0=> Secure state <1=> Non-Secure state +// GFXMMU_IRQn <0=> Secure state <1=> Non-Secure state +// LTDC_IRQn <0=> Secure state <1=> Non-Secure state +// LTDC_ER_IRQn <0=> Secure state <1=> Non-Secure state +// DSI_IRQn <0=> Secure state <1=> Non-Secure state +// DCACHE2_IRQn <0=> Secure state <1=> Non-Secure state +*/ +#define NVIC_INIT_ITNS4_VAL 0x00000000 + +/* +// +*/ + +/* +// +*/ + +/* + max 8 SAU regions. + SAU regions are defined in partition.h + */ + +#define SAU_INIT_REGION(n) \ + SAU->RNR = (n & SAU_RNR_REGION_Msk); \ + SAU->RBAR = (SAU_INIT_START##n & SAU_RBAR_BADDR_Msk); \ + SAU->RLAR = (SAU_INIT_END##n & SAU_RLAR_LADDR_Msk) | \ + ((SAU_INIT_NSC##n << SAU_RLAR_NSC_Pos) & SAU_RLAR_NSC_Msk) | 1U + +extern void trustzone_init(void); + +extern void trustzone_run(void); + +#endif +#endif diff --git a/core/embed/trezorhal/unix/platform.h b/core/embed/trezorhal/unix/platform.h index 0cab1411c1..29f0a4ddd5 100644 --- a/core/embed/trezorhal/unix/platform.h +++ b/core/embed/trezorhal/unix/platform.h @@ -1,2 +1,4 @@ +#define SENSITIVE + void emulator_poll_events(void); diff --git a/core/site_scons/boards/stm32f4_common.py b/core/site_scons/boards/stm32f4_common.py index 7f6fd0c1ad..7d881d3981 100644 --- a/core/site_scons/boards/stm32f4_common.py +++ b/core/site_scons/boards/stm32f4_common.py @@ -41,6 +41,7 @@ def stm32f4_common_files(env, defines, sources, paths): sources += [ "embed/trezorhal/stm32f4/board_capabilities.c", "embed/trezorhal/stm32f4/common.c", + "embed/trezorhal/stm32f4/fault_handlers.c", "embed/trezorhal/stm32f4/flash.c", "embed/trezorhal/stm32f4/lowlevel.c", "embed/trezorhal/stm32f4/mpu.c", @@ -51,6 +52,7 @@ def stm32f4_common_files(env, defines, sources, paths): "embed/trezorhal/stm32f4/rng.c", "embed/trezorhal/stm32f4/vectortable.s", "embed/trezorhal/stm32f4/translations.c", + "vendor/trezor-storage/flash_common_f4.c", ] # boardloader needs separate assembler for some function unencumbered by various FW+bootloader hacks @@ -71,6 +73,10 @@ def stm32f4_common_files(env, defines, sources, paths): "-I../../vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include;" "-I../../vendor/micropython/lib/cmsis/inc;" "-DSTM32_HAL_H=;" + "-DSTM32F4;" "-DFLASH_BLOCK_WORDS=1;" "-DFLASH_BIT_ACCESS=1" ) + + env.get("ENV")["SUFFIX"] = "stm32f4" + env.get("ENV")["LINKER_SCRIPT"] = "stm32f4" diff --git a/core/site_scons/boards/stm32u5_common.py b/core/site_scons/boards/stm32u5_common.py new file mode 100644 index 0000000000..c5e74f414f --- /dev/null +++ b/core/site_scons/boards/stm32u5_common.py @@ -0,0 +1,91 @@ +from __future__ import annotations + + +def stm32u5_common_files(env, defines, sources, paths): + defines += [ + ("STM32_HAL_H", '""'), + ("FLASH_BLOCK_WORDS", "4"), + ] + + paths += [ + "embed/trezorhal/stm32u5", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Inc", + "vendor/stm32cube-u5/Drivers/CMSIS/Device/ST/STM32U5xx/Include", + "vendor/stm32cube-u5/Drivers/CMSIS/Core/Include", + ] + + sources += [ + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_cortex.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_cryp.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_dma.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_dma2d.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_dsi.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_flash.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_flash_ex.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_gfxmmu.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_gpio.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_gtzc.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_i2c.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_i2c_ex.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_icache.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_ltdc.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_ltdc_ex.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_pcd.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_pcd_ex.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_pwr.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_pwr_ex.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_rcc.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_rcc_ex.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_rtc.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_sd.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_spi.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_sram.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_tim.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_tim_ex.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_ll_fmc.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_ll_sdmmc.c", + ] + + sources += [ + "embed/trezorhal/stm32u5/board_capabilities.c", + "embed/trezorhal/stm32u5/common.c", + "embed/trezorhal/stm32u5/fault_handlers.c", + "embed/trezorhal/stm32u5/flash.c", + "embed/trezorhal/stm32u5/lowlevel.c", + "embed/trezorhal/stm32u5/mpu.c", + "embed/trezorhal/stm32u5/platform.c", + "embed/trezorhal/stm32u5/secret.c", + "embed/trezorhal/stm32u5/secure_aes.c", + "embed/trezorhal/stm32u5/systick.c", + "embed/trezorhal/stm32f4/supervise.c", + "embed/trezorhal/stm32u5/random_delays.c", + "embed/trezorhal/stm32u5/rng.c", + "embed/trezorhal/stm32u5/tamper.c", + "embed/trezorhal/stm32u5/trustzone.c", + "embed/trezorhal/stm32u5/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 "limited_util_s" in env_constraints: + sources += [ + "embed/trezorhal/stm32u5/limited_util.s", + ] + else: + sources += [ + "embed/trezorhal/stm32u5/util.s", + ] + + env.get("ENV")["RUST_INCLUDES"] = ( + "-I../trezorhal/stm32u5;" + "-I../../vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Inc;" + "-I../../vendor/stm32cube-u5/Drivers/CMSIS/Device/ST/STM32U5xx/Include;" + "-I../../vendor/stm32cube-u5/Drivers/CMSIS/Core/Include;" + "-DSTM32_HAL_H=;" + "-DSTM32U5;" + "-DFLASH_BLOCK_WORDS=4" + ) + + env.get("ENV")["SUFFIX"] = "stm32u5" diff --git a/core/tools/combine_firmware b/core/tools/combine_firmware index 046d2f275d..a1ae841c85 100755 --- a/core/tools/combine_firmware +++ b/core/tools/combine_firmware @@ -9,12 +9,6 @@ from pathlib import Path import click -BOARDLOADER_START = 0x08000000 -BOARDLOADER_END = 0x0800C000 -BOOTLOADER_START = 0x08020000 -FIRMWARE_START = 0x08040000 - - @click.command() @click.argument( "boardloader", @@ -33,39 +27,75 @@ FIRMWARE_START = 0x08040000 type=click.Path(dir_okay=False, writable=True, path_type=Path), required=False, ) +@click.argument( + "boardloader_start", + type=click.STRING, + required=False, + default="0x08000000", +) +@click.argument( + "boardloader_end", + type=click.STRING, + required=False, + default="0x0800C000", +) +@click.argument( + "bootloader_start", + type=click.STRING, + required=False, + default="0x08020000", +) +@click.argument( + "firmware_start", + type=click.STRING, + required=False, + default="0x08040000", +) def main( - boardloader: Path, bootloader: Path, firmware: Path, outfile: Path | None + boardloader: Path, + bootloader: Path, + firmware: Path, + outfile: Path | None, + boardloader_start: str, + boardloader_end: str, + bootloader_start: str, + firmware_start: str, ) -> None: + boardloader_start = int(boardloader_start, 0) + boardloader_end = int(boardloader_end, 0) + bootloader_start = int(bootloader_start, 0) + firmware_start = int(firmware_start, 0) + if outfile is None: today = datetime.date.today().strftime(r"%Y-%m-%d") outfile = Path(f"combined-{today}.bin") - offset = BOARDLOADER_START + offset = boardloader_start out_bytes = io.BytesIO() # write boardloader offset += out_bytes.write(boardloader.read_bytes()) - if offset > BOARDLOADER_END: + if offset > boardloader_end: raise Exception("Boardloader too big") # zero-pad until next section: - offset += out_bytes.write(b"\x00" * (BOOTLOADER_START - offset)) - assert offset == BOOTLOADER_START + offset += out_bytes.write(b"\x00" * (bootloader_start - offset)) + assert offset == bootloader_start # write bootlaoder offset += out_bytes.write(bootloader.read_bytes()) - if offset > FIRMWARE_START: + if offset > firmware_start: raise Exception("Bootloader too big") # zero-pad until next section: - offset += out_bytes.write(b"\x00" * (FIRMWARE_START - offset)) - assert offset == FIRMWARE_START + offset += out_bytes.write(b"\x00" * (firmware_start - offset)) + assert offset == firmware_start # write firmware offset += out_bytes.write(firmware.read_bytes()) # write out contents - click.echo(f"Writing {outfile} ({offset - BOARDLOADER_START} bytes)") + click.echo(f"Writing {outfile} ({offset - boardloader_start} bytes)") outfile.write_bytes(out_bytes.getvalue()) diff --git a/legacy/Makefile b/legacy/Makefile index 0a9354e036..7795fd21e6 100644 --- a/legacy/Makefile +++ b/legacy/Makefile @@ -20,7 +20,7 @@ OBJS += usb_standard.o OBJS += util.o OBJS += webusb.o OBJS += winusb.o -OBJS += vendor/trezor-storage/flash_common.o +OBJS += vendor/trezor-storage/flash_common_f4.o libtrezor.a: $(OBJS) diff --git a/storage/flash_common.h b/storage/flash_common.h index 763882d2b2..4d69f0c6eb 100644 --- a/storage/flash_common.h +++ b/storage/flash_common.h @@ -1,6 +1,7 @@ #ifndef FLASH_COMMON_H #define FLASH_COMMON_H +#include #include #include "secbool.h" @@ -12,6 +13,7 @@ typedef struct { typedef struct { flash_subarea_t subarea[4]; uint8_t num_subareas; + bool secure_area; } flash_area_t; #define FLASH_BLOCK_SIZE (sizeof(uint32_t) * FLASH_BLOCK_WORDS) @@ -59,4 +61,7 @@ secbool __wur flash_area_write_block(const flash_area_t *area, uint32_t offset, secbool flash_write_block(uint16_t sector, uint32_t offset, const flash_block_t block); +secbool __wur flash_area_write_burst(const flash_area_t *area, uint32_t offset, + const uint32_t *data); + #endif diff --git a/storage/flash_common.c b/storage/flash_common_f4.c similarity index 91% rename from storage/flash_common.c rename to storage/flash_common_f4.c index 9b38c44d74..8caec528de 100644 --- a/storage/flash_common.c +++ b/storage/flash_common_f4.c @@ -137,3 +137,17 @@ secbool flash_area_write_block(const flash_area_t *area, uint32_t offset, return flash_write_block(sector, sector_offset, block); } + +secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset, + const uint32_t *data) { + if (offset % (8 * 16) != 0) { + return secfalse; + } + for (int i = 0; i < (8 * 4); i++) { + if (sectrue != + flash_area_write_word(area, offset + i * sizeof(uint32_t), data[i])) { + return secfalse; + } + } + return sectrue; +} diff --git a/storage/tests/c/Makefile b/storage/tests/c/Makefile index 099b84d041..159c480f42 100644 --- a/storage/tests/c/Makefile +++ b/storage/tests/c/Makefile @@ -14,7 +14,7 @@ SRC = storage/tests/c/flash.c SRC += storage/tests/c/common.c SRC += storage/tests/c/random_delays.c SRC += storage/tests/c/test_layout.c -SRC += storage/flash_common.c +SRC += storage/flash_common_f4.c SRC += storage/storage.c SRC += storage/storage_utils.c SRC += storage/norcow.c