diff --git a/Makefile b/Makefile index 1daba0dad5b..693d62e4b62 100644 --- a/Makefile +++ b/Makefile @@ -154,6 +154,12 @@ bootloader_hashes: ## generate bootloader hashes bootloader_hashes_check: ## check generated bootloader hashes ./core/tools/bootloader_hashes.py --check -gen: templates mocks icons protobuf ci_docs vendorheader solana_templates bootloader_hashes ## regenerate auto-generated files from sources +lsgen: ## generate linker scripts hashes + lsgen -gen_check: templates_check mocks_check icons_check protobuf_check ci_docs_check vendorheader_check solana_templates_check bootloader_hashes_check ## check validity of auto-generated files +lsgen_check: ## check generated linker scripts + lsgen --check + +gen: templates mocks icons protobuf ci_docs vendorheader solana_templates bootloader_hashes lsgen ## regenerate auto-generated files from sources + +gen_check: templates_check mocks_check icons_check protobuf_check ci_docs_check vendorheader_check solana_templates_check bootloader_hashes_check lsgen_check ## check validity of auto-generated files diff --git a/core/Makefile b/core/Makefile index e6647bf5e71..f89b0821812 100644 --- a/core/Makefile +++ b/core/Makefile @@ -18,6 +18,7 @@ BOOTLOADER_CI_BUILD_DIR = $(BUILD_DIR)/bootloader_ci BOOTLOADER_EMU_BUILD_DIR = $(BUILD_DIR)/bootloader_emu PRODTEST_BUILD_DIR = $(BUILD_DIR)/prodtest REFLASH_BUILD_DIR = $(BUILD_DIR)/reflash +KERNEL_BUILD_DIR = $(BUILD_DIR)/kernel FIRMWARE_BUILD_DIR = $(BUILD_DIR)/firmware UNIX_BUILD_DIR = $(BUILD_DIR)/unix RUST_BUILD_DIR = $(BUILD_DIR)/rust @@ -78,6 +79,7 @@ endif FLASH_START = $(shell layout_parser ${TREZOR_MODEL} FLASH_START) BOARDLOADER_START = $(shell layout_parser ${TREZOR_MODEL} BOARDLOADER_START) BOOTLOADER_START = $(shell layout_parser ${TREZOR_MODEL} BOOTLOADER_START) +KERNEL_START = $(shell layout_parser ${TREZOR_MODEL} KERNEL_START) FIRMWARE_START = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_START) FIRMWARE_P2_START = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_P2_START) STORAGE_1_OFFSET = $(shell layout_parser ${TREZOR_MODEL} STORAGE_1_OFFSET) @@ -143,6 +145,7 @@ test: ## run unit tests cd tests ; ./run_tests.sh $(TESTOPTS) test_rust: ## run rs unit tests + export BUILD_DIR=$(abspath $(UNIX_BUILD_DIR)) ; \ cd embed/rust ; cargo test $(TESTOPTS) --target=$(RUST_TARGET) \ --no-default-features --features $(MODEL_FEATURE),test \ -- --test-threads=1 --nocapture @@ -212,6 +215,7 @@ pyright: python ../tools/pyright_tool.py clippy: + export BUILD_DIR=$(abspath $(UNIX_BUILD_DIR)) ; \ cd embed/rust ; cargo clippy $(TESTOPTS) --all-features --target=$(RUST_TARGET) ## code generation: @@ -268,7 +272,13 @@ build_reflash: ## build reflash firmware + reflash image dd if=build/boardloader/boardloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=0 dd if=build/bootloader/bootloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=49152 -build_firmware: templates build_cross ## build firmware with frozen modules +build_kernel: ## build kernel image + $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" \ + TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \ + BOOTLOADER_QA="$(BOOTLOADER_QA)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" \ + $(KERNEL_BUILD_DIR)/kernel.bin + +build_firmware: templates build_cross build_kernel ## build firmware with frozen modules $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" \ TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \ PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" \ @@ -320,6 +330,9 @@ clean_prodtest: ## clean prodtest build clean_reflash: ## clean reflash build rm -rf $(REFLASH_BUILD_DIR) +clean_kernel: ## clean kernel build + rm -rf $(KERNEL_BUILD_DIR) + clean_firmware: ## clean firmware build rm -rf $(FIRMWARE_BUILD_DIR) $(RUST_BUILD_DIR) diff --git a/core/SConscript.boardloader b/core/SConscript.boardloader index cc31e0b6b8d..8afc63e7d46 100644 --- a/core/SConscript.boardloader +++ b/core/SConscript.boardloader @@ -7,6 +7,7 @@ TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) HW_REVISION = ARGUMENTS.get('HW_REVISION', None) NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' +MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL) if TREZOR_MODEL in ('1', ): # skip boardloader build @@ -41,6 +42,7 @@ CPPPATH_MOD += [ 'vendor/trezor-storage', ] CPPDEFINES_MOD += [ + 'KERNEL_MODE', 'AES_128', 'AES_192', 'USE_KECCAK', @@ -69,6 +71,7 @@ SOURCE_MOD += [ 'embed/lib/colors.c', 'embed/lib/display_utils.c', 'embed/lib/error_handling.c', + 'embed/lib/flash_utils.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', 'embed/lib/gfx_color.c', @@ -77,6 +80,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', ] if NEW_RENDERING: @@ -100,15 +104,15 @@ env = Environment(ENV=os.environ, FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, 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", + f"embed/trezorhal/{FILE_SUFFIX}/startup_stage_0.s", 'embed/boardloader/main.c', ] env.Replace( + CAT='cat', CP='cp', AS='arm-none-eabi-as', AR='arm-none-eabi-ar', @@ -134,7 +138,7 @@ env.Replace( '-fstack-protector-strong ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - 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", + LINKFLAGS="-T build/boardloader/memory.ld -Wl,--gc-sections -Wl,-Map=build/boardloader/boardloader.map -Wl,--warn-common -Wl,--print-memory-usage", CPPPATH=[ 'embed/boardloader', 'embed/lib', @@ -172,6 +176,12 @@ obj_program += env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial- obj_program += env.Object(source=SOURCE_BOARDLOADER) obj_program += env.Object(source=SOURCE_HAL) +linkerscript_gen = env.Command( + target='memory.ld', + source=[f'embed/models/{MODEL_IDENTIFIER}/memory.ld', env.get('ENV')['LINKER_SCRIPT'].format(target='boardloader')], + action='$CAT $SOURCES > $TARGET', +) + program_elf = env.Command( target='boardloader.elf', source=obj_program, @@ -179,6 +189,8 @@ program_elf = env.Command( '$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES -lc_nano -lgcc', ) +env.Depends(program_elf, linkerscript_gen) + BINARY_NAME = f"build/boardloader/boardloader-{models.get_model_identifier(TREZOR_MODEL)}" BINARY_NAME += "-" + tools.get_version('embed/boardloader/version.h') BINARY_NAME += "-" + tools.get_git_revision_short_hash() diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index e5226cd3139..b0a52822eca 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -9,6 +9,7 @@ BOOTLOADER_QA = ARGUMENTS.get('BOOTLOADER_QA', '0') == '1' PRODUCTION = 0 if BOOTLOADER_QA else ARGUMENTS.get('PRODUCTION', '0') == '1' HW_REVISION = ARGUMENTS.get('HW_REVISION', None) NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' or TREZOR_MODEL in ('T3T1',) +MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL) if TREZOR_MODEL in ('1', ): # skip bootloader build @@ -71,6 +72,7 @@ CPPPATH_MOD += [ 'vendor/trezor-storage', ] CPPDEFINES_MOD += [ + 'KERNEL_MODE', 'AES_128', 'AES_192', 'USE_KECCAK', @@ -108,6 +110,7 @@ SOURCE_MOD += [ 'embed/lib/colors.c', 'embed/lib/display_utils.c', 'embed/lib/error_handling.c', + 'embed/lib/flash_utils.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', 'embed/lib/gfx_color.c', @@ -116,6 +119,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_rgba8888.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'embed/lib/unit_variant.c', 'vendor/micropython/lib/uzlib/adler32.c', @@ -159,10 +163,9 @@ env = Environment( FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, 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', + f'embed/trezorhal/{FILE_SUFFIX}/startup_stage_1.s', 'embed/bootloader/header.S', 'embed/bootloader/bootui.c', 'embed/bootloader/main.c', @@ -173,6 +176,7 @@ SOURCE_BOOTLOADER = [ env.Replace( + CAT='cat', CP='cp', AS='arm-none-eabi-as', AR='arm-none-eabi-ar', @@ -210,7 +214,7 @@ env.Replace( '-fstack-protector-strong ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - 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', + LINKFLAGS='-T build/bootloader/memory.ld -Wl,--gc-sections -Wl,-Map=build/bootloader/bootloader.map -Wl,--warn-common -Wl,--print-memory-usage', CPPPATH=ALLPATHS, CPPDEFINES=[ 'BOOTLOADER', @@ -283,8 +287,9 @@ def cargo_build(): ] bindgen_macros = tools.get_bindgen_defines(env.get("CPPDEFINES"), ALLPATHS) + build_dir = str(Dir('.').abspath) - return f'export BINDGEN_MACROS=\'{bindgen_macros}\'; cd embed/rust; cargo build {profile} ' + ' '.join(cargo_opts) + return f'export BINDGEN_MACROS=\'{bindgen_macros}\'; export BUILD_DIR=\'{build_dir}\'; cd embed/rust; cargo build {profile} ' + ' '.join(cargo_opts) rust = env.Command( target=RUST_LIBPATH, @@ -306,6 +311,12 @@ obj_program += env.Object(source=SOURCE_NANOPB) obj_program += env.Object(source=SOURCE_HAL) +linkerscript_gen = env.Command( + target='memory.ld', + source=[f'embed/models/{MODEL_IDENTIFIER}/memory.ld', env.get('ENV')['LINKER_SCRIPT'].format(target='bootloader')], + action='$CAT $SOURCES > $TARGET', +) + program_elf = env.Command( target='bootloader.elf', source=obj_program, @@ -313,6 +324,7 @@ program_elf = env.Command( '$LINK -o $TARGET $CCFLAGS $CFLAGS $SOURCES $LINKFLAGS -lc_nano -lm -lgcc', ) +env.Depends(program_elf, linkerscript_gen) env.Depends(program_elf, rust) SUFFIX = '_qa' if BOOTLOADER_QA else '' diff --git a/core/SConscript.bootloader_ci b/core/SConscript.bootloader_ci index 93f9277bd9e..1963c53600d 100644 --- a/core/SConscript.bootloader_ci +++ b/core/SConscript.bootloader_ci @@ -7,6 +7,7 @@ TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) HW_REVISION = ARGUMENTS.get('HW_REVISION', None) NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' or TREZOR_MODEL in ('T3T1',) +MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL) if TREZOR_MODEL in ('1', 'DISC1', 'DISC2'): # skip bootloader_ci build @@ -69,6 +70,7 @@ CPPPATH_MOD += [ 'vendor/trezor-storage', ] CPPDEFINES_MOD += [ + 'KERNEL_MODE', 'AES_128', 'AES_192', 'USE_KECCAK', @@ -101,6 +103,7 @@ SOURCE_MOD += [ 'embed/lib/colors.c', 'embed/lib/display_utils.c', 'embed/lib/error_handling.c', + 'embed/lib/flash_utils.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', 'embed/lib/gfx_color.c', @@ -109,6 +112,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_rgba8888.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', @@ -151,10 +155,9 @@ env = Environment( FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, 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', + f'embed/trezorhal/{FILE_SUFFIX}/startup_stage_1.s', 'embed/bootloader_ci/header.S', 'embed/bootloader_ci/bootui.c', 'embed/bootloader_ci/main.c', @@ -164,6 +167,7 @@ SOURCE_BOOTLOADER = [ ] env.Replace( + CAT='cat', CP='cp', AS='arm-none-eabi-as', AR='arm-none-eabi-ar', @@ -189,7 +193,7 @@ env.Replace( '-fstack-protector-strong ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS=f'-T embed/bootloader_ci/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/bootloader_ci/bootloader.map -Wl,--warn-common', + LINKFLAGS=f'-T build/bootloader_ci/memory.ld -Wl,--gc-sections -Wl,-Map=build/bootloader_ci/bootloader.map -Wl,--warn-common', CPPPATH=[ 'embed/bootloader_ci', 'embed/bootloader_ci/nanopb', @@ -238,6 +242,12 @@ obj_program += env.Object(source=SOURCE_BOOTLOADER) obj_program += env.Object(source=SOURCE_NANOPB) obj_program += env.Object(source=SOURCE_HAL) +linkerscript_gen = env.Command( + target='memory.ld', + source=[f'embed/models/{MODEL_IDENTIFIER}/memory.ld', env.get('ENV')['LINKER_SCRIPT'].format(target='bootloader')], + action='$CAT $SOURCES > $TARGET', +) + program_elf = env.Command( target='bootloader.elf', source=obj_program, @@ -245,6 +255,8 @@ program_elf = env.Command( '$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES -lc_nano -lgcc', ) +env.Depends(program_elf, linkerscript_gen) + BINARY_NAME = f"build/bootloader_ci/bootloader_ci-{models.get_model_identifier(TREZOR_MODEL)}" BINARY_NAME += "-" + tools.get_version('embed/bootloader_ci/version.h') BINARY_NAME += "-" + tools.get_git_revision_short_hash() diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu index 9d0627cbcc7..a98ae71d514 100644 --- a/core/SConscript.bootloader_emu +++ b/core/SConscript.bootloader_emu @@ -68,6 +68,7 @@ CPPPATH_MOD += [ 'vendor/trezor-storage', ] CPPDEFINES_MOD += [ + 'KERNEL_MODE', 'AES_128', 'AES_192', 'USE_KECCAK', @@ -103,6 +104,7 @@ SOURCE_MOD += [ 'embed/lib/colors.c', 'embed/lib/display_utils.c', 'embed/lib/error_handling.c', + 'embed/lib/flash_utils.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', 'embed/lib/gfx_color.c', @@ -111,6 +113,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_rgba8888.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'embed/lib/unit_variant.c', 'vendor/micropython/lib/uzlib/adler32.c', @@ -145,15 +148,18 @@ SOURCE_BOOTLOADER = [ ] SOURCE_TREZORHAL = [ - 'embed/trezorhal/unix/boot_args.c', + 'embed/trezorhal/unix/bootutils.c', 'embed/trezorhal/unix/common.c', - 'embed/trezorhal/unix/fault_handlers.c', 'embed/trezorhal/unix/flash.c', 'embed/trezorhal/unix/flash_otp.c', + 'embed/trezorhal/unix/mpu.c', 'embed/trezorhal/unix/monoctr.c', 'embed/trezorhal/unix/random_delays.c', 'embed/trezorhal/unix/rng.c', 'embed/trezorhal/unix/secret.c', + 'embed/trezorhal/unix/system.c', + 'embed/trezorhal/unix/systick.c', + 'embed/trezorhal/unix/systimer.c', 'embed/trezorhal/unix/usb.c', ] @@ -300,8 +306,9 @@ def cargo_build(): ] bindgen_macros = tools.get_bindgen_defines(env.get("CPPDEFINES"), ALLPATHS) + build_dir = str(Dir('.').abspath) - return f'export BINDGEN_MACROS=\'{bindgen_macros}\'; cd embed/rust; cargo build --profile {RUST_PROFILE} ' + ' '.join(cargo_opts) + return f'export BINDGEN_MACROS=\'{bindgen_macros}\'; export BUILD_DIR=\'{build_dir}\'; cd embed/rust; cargo build --profile {RUST_PROFILE} ' + ' '.join(cargo_opts) rust = env.Command( target=RUST_LIBPATH, diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 2431309f022..652a21f518b 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -16,12 +16,11 @@ DISABLE_OPTIGA = ARGUMENTS.get('DISABLE_OPTIGA', '0') == '1' HW_REVISION = ARGUMENTS.get('HW_REVISION', None) THP = ARGUMENTS.get('THP', '0') == '1' # Trezor-Host Protocol NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' - +MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL) FEATURE_FLAGS = { "RDI": True, "SECP256K1_ZKP": True, # required for trezor.crypto.curve.bip340 (BIP340/Taproot) - "SYSTEM_VIEW": False, "AES_GCM": False, } @@ -77,10 +76,6 @@ CPPPATH_MOD += [ ] SOURCE_MOD += [ 'embed/extmod/modtrezorconfig/modtrezorconfig.c', - 'vendor/trezor-storage/norcow.c', - 'vendor/trezor-storage/storage.c', - 'vendor/trezor-storage/storage_utils.c', - 'vendor/trezor-storage/flash_area.c', ] # modtrezorcrypto @@ -236,6 +231,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'embed/lib/translations.c', 'embed/lib/unit_variant.c', @@ -295,7 +291,6 @@ SOURCE_MICROPYTHON = [ 'vendor/micropython/shared/runtime/stdout_helpers.c', 'vendor/micropython/shared/timeutils/timeutils.c', 'vendor/micropython/ports/stm32/gccollect.c', - 'vendor/micropython/ports/stm32/pendsv.c', 'vendor/micropython/py/argcheck.c', 'vendor/micropython/py/asmarm.c', 'vendor/micropython/py/asmbase.c', @@ -402,22 +397,6 @@ CPPDEFINES_MOD += ['USE_SVC_SHUTDOWN'] if FEATURE_FLAGS["RDI"]: CPPDEFINES_MOD += ['RDI'] -if FEATURE_FLAGS["SYSTEM_VIEW"]: - SOURCE_FIRMWARE += [ - 'embed/segger/SEGGER/SEGGER_SYSVIEW_Config_NoOS.c', - 'embed/segger/SEGGER/SEGGER_SYSVIEW.c', - 'embed/segger/SEGGER/SEGGER_RTT.c', - 'embed/segger/SEGGER/SEGGER_RTT_ASM_ARMv7M.S', - 'embed/segger/SEGGER/Syscalls/SEGGER_RTT_Syscalls_GCC.c', - 'embed/firmware/systemview.c', - ] - CPPPATH_MOD += [ - 'embed/segger/SEGGER/', - 'embed/segger/Config/', - ] - CPPDEFINES_MOD += ['SYSTEM_VIEW'] - CCFLAGS_MOD += '-DSYSTEM_VIEW ' - TRANSLATION_DATA = [ "translations/en.json", "translations/order.json", @@ -452,13 +431,11 @@ FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_ 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', + f'embed/trezorhal/{FILE_SUFFIX}/startup_stage_4.s', ] @@ -497,11 +474,6 @@ env.Replace( env.Replace( TREZOR_MODEL=TREZOR_MODEL,) -if TREZOR_MODEL in ('1',): - LD_VARIANT = '' if EVERYTHING else '_min' -else: - LD_VARIANT = '' - ALLPATHS = [ '.', 'embed/rust', @@ -524,7 +496,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/firmware/memory_${TREZOR_MODEL}%s.ld -Wl,--gc-sections -Wl,--print-memory-usage -Wl,-Map=build/firmware/firmware.map -Wl,--warn-common' % LD_VARIANT, + LINKFLAGS='-T build/firmware/memory.ld -Wl,--gc-sections -Wl,--print-memory-usage -Wl,-Map=build/firmware/firmware.map -Wl,--warn-common', CPPPATH=ALLPATHS, CPPDEFINES=[ 'FIRMWARE', @@ -862,8 +834,9 @@ def cargo_build(): env.get('ENV')['TREZOR_MODEL'] = TREZOR_MODEL bindgen_macros = tools.get_bindgen_defines(env.get("CPPDEFINES"), ALLPATHS) + build_dir = str(Dir('.').abspath) - return f'export BINDGEN_MACROS=\'{bindgen_macros}\'; cd embed/rust; cargo build {profile} ' + ' '.join(cargo_opts) + return f'export BINDGEN_MACROS=\'{bindgen_macros}\'; export BUILD_DIR=\'{build_dir}\'; cd embed/rust; cargo build {profile} ' + ' '.join(cargo_opts) rust = env.Command( target=RUST_LIBPATH, @@ -897,27 +870,33 @@ else: VENDORHEADER = f'embed/models/{MODEL_IDENTIFIER}/vendorheader/vendorheader_{vendor}.bin' -if TREZOR_MODEL not in ('1',): - obj_program.extend( - env.Command( - target='embed/firmware/vendorheader.o', - source=VENDORHEADER, - action='$OBJCOPY -I binary -O elf32-littlearm -B arm' - ' --rename-section .data=.vendorheader,alloc,load,readonly,contents' - ' $SOURCE $TARGET', )) +obj_program.extend( + env.Command( + target='embed/firmware/vendorheader.o', + source=VENDORHEADER, + action='$OBJCOPY -I binary -O elf32-littlearm -B arm' + ' --rename-section .data=.vendorheader,alloc,load,readonly,contents' + ' $SOURCE $TARGET', )) + + +tools.embed_raw_binary( + obj_program, + env, + 'kernel', + 'build/kernel/kernel.o', + f'build/kernel/kernel.bin', + ) -if TREZOR_MODEL not in ('DISC1', 'DISC2'): - tools.embed_binary( - obj_program, - env, - 'bootloader', - 'embed/firmware/bootloaders/bootloader.o', - f'embed/models/{MODEL_IDENTIFIER}/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin', - ) env.Depends(obj_program, qstr_generated) +linkerscript_gen = env.Command( + target='memory.ld', + source=[f'embed/models/{MODEL_IDENTIFIER}/memory.ld', env.get('ENV')['LINKER_SCRIPT'].format(target='firmware')], + action='$CAT $SOURCES > $TARGET', +) + program_elf = env.Command( target='firmware.elf', source=obj_program, @@ -925,11 +904,13 @@ program_elf = env.Command( '$LINK -o $TARGET $CCFLAGS $CFLAGS $SOURCES $LINKFLAGS -lc_nano -lm -lgcc', ) +env.Depends(program_elf, linkerscript_gen) + if CMAKELISTS != 0: env.Depends(program_elf, cmake_gen) env.Depends(program_elf, rust) -BINARY_NAME = f"build/firmware/firmware-{models.get_model_identifier(TREZOR_MODEL)}" +BINARY_NAME = f"build/firmware/firmware-{MODEL_IDENTIFIER}" if not EVERYTHING: BINARY_NAME += "-btconly" BINARY_NAME += "-" + tools.get_version('embed/firmware/version.h') @@ -938,30 +919,23 @@ BINARY_NAME += "-dirty" if tools.get_git_modified() else "" BINARY_NAME += ".bin" -if TREZOR_MODEL in ('1'): +if 'STM32F427xx' in CPPDEFINES_HAL or 'STM32F429xx' in CPPDEFINES_HAL: action_bin=[ - '$OBJCOPY -O binary -j .header -j .flash -j .data -j .confidential $SOURCE $TARGET', - '../legacy/bootloader/firmware_sign.py -f $TARGET', + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .confidential --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, ] -else: - if 'STM32F427xx' in CPPDEFINES_HAL or 'STM32F429xx' in CPPDEFINES_HAL: - action_bin=[ - '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .confidential --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 or 'STM32U585xx' in CPPDEFINES_HAL: + action_bin=[ + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .confidential $SOURCE ${TARGET}', + '$HEADERTOOL -h $TARGET ' + ('-D' if not PRODUCTION else ''), + '$CP $TARGET ' + BINARY_NAME, ] - elif 'STM32U5A9xx' in CPPDEFINES_HAL or 'STM32U585xx' in CPPDEFINES_HAL: - action_bin=[ - '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .confidential $SOURCE ${TARGET}', - '$HEADERTOOL -h $TARGET ' + ('-D' if not PRODUCTION else ''), - '$CP $TARGET ' + BINARY_NAME, - ] - else: - raise Exception("Unknown MCU") +else: + raise Exception("Unknown MCU") program_bin = env.Command( target='firmware.bin', diff --git a/core/SConscript.kernel b/core/SConscript.kernel new file mode 100644 index 00000000000..aff585b0b15 --- /dev/null +++ b/core/SConscript.kernel @@ -0,0 +1,434 @@ +# pylint: disable=E0602 +# fmt: off + +import os +import tools, models + +BITCOIN_ONLY = ARGUMENTS.get('BITCOIN_ONLY', '0') +PRODUCTION = ARGUMENTS.get('PRODUCTION', '0') == '1' +BOOTLOADER_QA = ARGUMENTS.get('BOOTLOADER_QA', '0') == '1' +BOOTLOADER_DEVEL = ARGUMENTS.get('BOOTLOADER_DEVEL', '0') == '1' +EVERYTHING = BITCOIN_ONLY != '1' +TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') +CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) +PYOPT = ARGUMENTS.get('PYOPT', '1') +DISABLE_OPTIGA = ARGUMENTS.get('DISABLE_OPTIGA', '0') == '1' +HW_REVISION = ARGUMENTS.get('HW_REVISION', None) +THP = ARGUMENTS.get('THP', '0') == '1' # Trezor-Host Protocol +NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' or TREZOR_MODEL in ('T3T1',) + + +FEATURE_FLAGS = { + "RDI": True, + "SECP256K1_ZKP": True, # required for trezor.crypto.curve.bip340 (BIP340/Taproot) + "SYSTEM_VIEW": False, + "AES_GCM": False, +} + +FEATURES_WANTED = ["input", "sbu", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga", "haptic"] +if DISABLE_OPTIGA and PYOPT == '0': + FEATURES_WANTED.remove("optiga") +if NEW_RENDERING: + FEATURES_WANTED.append("new_rendering") + +CCFLAGS_MOD = '' +CPPPATH_MOD = [] +CPPDEFINES_MOD = [] +SOURCE_MOD = [] +SOURCE_MOD_CRYPTO = [] +CPPDEFINES_HAL = [] +SOURCE_HAL = [] +PATH_HAL = [] + +FROZEN = True + +# modtrezorconfig +CPPPATH_MOD += [ + 'embed/extmod/modtrezorconfig', + 'vendor/trezor-storage', + 'vendor/micropython/lib/uzlib', +] +SOURCE_MOD += [ +# 'embed/extmod/modtrezorconfig/modtrezorconfig.c', + 'vendor/trezor-storage/norcow.c', + 'vendor/trezor-storage/storage.c', + 'vendor/trezor-storage/storage_utils.c', + 'vendor/trezor-storage/flash_area.c', +] + +# modtrezorcrypto +CCFLAGS_MOD += '-Wno-sequence-point ' +CPPPATH_MOD += [ + 'vendor/trezor-crypto', +] +CPPDEFINES_MOD += [ + 'KERNEL_MODE', + 'SYSCALL_DISPATCH', + 'AES_128', + 'AES_192', + ('USE_BIP32_CACHE', '0'), + ('USE_KECCAK', '1'), + ('USE_ETHEREUM', '1' if EVERYTHING else '0'), + ('USE_MONERO', '1' if EVERYTHING else '0'), + ('USE_CARDANO', '1' if EVERYTHING else '0'), + ('USE_NEM', '1' if (EVERYTHING and TREZOR_MODEL == "T") else '0'), + ('USE_EOS', '1' if (EVERYTHING and TREZOR_MODEL == "T") else '0'), +] +SOURCE_MOD_CRYPTO += [ + 'vendor/trezor-crypto/address.c', + 'vendor/trezor-crypto/aes/aes_modes.c', + 'vendor/trezor-crypto/aes/aesccm.c', + 'vendor/trezor-crypto/aes/aescrypt.c', + 'vendor/trezor-crypto/aes/aeskey.c', + 'vendor/trezor-crypto/aes/aestab.c', + 'vendor/trezor-crypto/base32.c', + 'vendor/trezor-crypto/base58.c', + 'vendor/trezor-crypto/bignum.c', + 'vendor/trezor-crypto/bip32.c', + 'vendor/trezor-crypto/bip39.c', + 'vendor/trezor-crypto/bip39_english.c', + 'vendor/trezor-crypto/blake256.c', + 'vendor/trezor-crypto/blake2b.c', + 'vendor/trezor-crypto/blake2s.c', + 'vendor/trezor-crypto/buffer.c', + 'vendor/trezor-crypto/chacha20poly1305/chacha20poly1305.c', + 'vendor/trezor-crypto/chacha20poly1305/chacha_merged.c', + 'vendor/trezor-crypto/chacha20poly1305/poly1305-donna.c', + 'vendor/trezor-crypto/chacha20poly1305/rfc7539.c', + 'vendor/trezor-crypto/chacha_drbg.c', + 'vendor/trezor-crypto/curves.c', + 'vendor/trezor-crypto/der.c', + 'vendor/trezor-crypto/ecdsa.c', + 'vendor/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c', + 'vendor/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c', + 'vendor/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c', + 'vendor/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c', + 'vendor/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c', + 'vendor/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c', + 'vendor/trezor-crypto/ed25519-donna/ed25519-keccak.c', + 'vendor/trezor-crypto/ed25519-donna/ed25519-sha3.c', + 'vendor/trezor-crypto/ed25519-donna/ed25519.c', + 'vendor/trezor-crypto/ed25519-donna/modm-donna-32bit.c', + 'vendor/trezor-crypto/groestl.c', + 'vendor/trezor-crypto/hasher.c', + 'vendor/trezor-crypto/hmac.c', + 'vendor/trezor-crypto/hmac_drbg.c', + 'vendor/trezor-crypto/memzero.c', + 'vendor/trezor-crypto/nem.c', + 'vendor/trezor-crypto/nist256p1.c', + 'vendor/trezor-crypto/pbkdf2.c', + 'vendor/trezor-crypto/rand.c', + 'vendor/trezor-crypto/rfc6979.c', + 'vendor/trezor-crypto/ripemd160.c', + 'vendor/trezor-crypto/secp256k1.c', + 'vendor/trezor-crypto/segwit_addr.c', + 'vendor/trezor-crypto/sha2.c', + 'vendor/trezor-crypto/sha3.c', + 'vendor/trezor-crypto/shamir.c', + 'vendor/trezor-crypto/slip39.c', + 'vendor/trezor-crypto/slip39_english.c', + 'vendor/trezor-crypto/tls_prf.c', +] +if EVERYTHING: + SOURCE_MOD_CRYPTO += [ + 'vendor/trezor-crypto/cardano.c', + 'vendor/trezor-crypto/monero/base58.c', + 'vendor/trezor-crypto/monero/serialize.c', + 'vendor/trezor-crypto/monero/xmr.c', + ] + +# libsecp256k1-zkp +if FEATURE_FLAGS["SECP256K1_ZKP"]: + CPPPATH_MOD += [ + 'vendor/secp256k1-zkp', + 'vendor/secp256k1-zkp/src', + 'vendor/secp256k1-zkp/include', + ] + CPPDEFINES_MOD += [ + 'USE_SECP256K1_ZKP', + 'USE_SECP256K1_ZKP_ECDSA', + ('SECP256K1_CONTEXT_SIZE', '180'), + 'USE_ASM_ARM', + 'USE_EXTERNAL_ASM', + 'USE_EXTERNAL_DEFAULT_CALLBACKS', + ('ECMULT_GEN_PREC_BITS', '2'), + ('ECMULT_WINDOW_SIZE', '2'), + 'ENABLE_MODULE_GENERATOR', + 'ENABLE_MODULE_RECOVERY', + 'ENABLE_MODULE_SCHNORRSIG', + 'ENABLE_MODULE_EXTRAKEYS', + 'ENABLE_MODULE_ECDH', + ] + SOURCE_MOD_SECP256K1_ZKP = [ + 'vendor/secp256k1-zkp/src/secp256k1.c', + 'vendor/secp256k1-zkp/src/precomputed_ecmult.c', + 'vendor/secp256k1-zkp/src/precomputed_ecmult_gen.c', + 'vendor/secp256k1-zkp/src/asm/field_10x26_arm.s' + ] + SOURCE_MOD_CRYPTO += [ + 'vendor/trezor-crypto/zkp_context.c', + 'vendor/trezor-crypto/zkp_ecdsa.c', + 'vendor/trezor-crypto/zkp_bip340.c', + ] + +# AES-GCM +if FEATURE_FLAGS["AES_GCM"]: + CPPDEFINES_MOD += [ + 'USE_AES_GCM', + 'AES_VAR', + ] + SOURCE_MOD_CRYPTO += [ + 'vendor/trezor-crypto/aes/gf128mul.c', + 'vendor/trezor-crypto/aes/aesgcm.c', + ] + +SOURCE_MOD += [ + 'embed/lib/bl_check.c', +# 'embed/lib/buffers.c', +# 'embed/lib/colors.c', +# 'embed/lib/display_utils.c', + 'embed/lib/error_handling.c', + 'embed/lib/fonts/font_bitmap.c', +# 'embed/lib/fonts/fonts.c', + 'embed/lib/gfx_color.c', + 'embed/lib/gfx_bitblt_rgb565.c', + 'embed/lib/gfx_bitblt_rgba8888.c', + 'embed/lib/gfx_bitblt_mono8.c', + 'embed/lib/image.c', + 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', + 'embed/lib/terminal.c', + 'embed/lib/translations.c', + 'embed/lib/unit_variant.c', + 'embed/extmod/modtrezorcrypto/rand.c', + 'vendor/micropython/lib/uzlib/adler32.c', + 'vendor/micropython/lib/uzlib/crc32.c', + 'vendor/micropython/lib/uzlib/tinflate.c', +] + +if NEW_RENDERING: + CPPDEFINES_MOD += ['NEW_RENDERING'] + SOURCE_MOD += [ + 'embed/lib/gfx_draw.c', + ] +else: + SOURCE_MOD += [ + 'embed/lib/display_draw.c', + ] + + +CPPDEFINES_MOD += [ + 'TRANSLATIONS', +] + +if TREZOR_MODEL not in ('1', ): + CPPDEFINES_MOD += [ + 'FANCY_FATAL_ERROR', + ] + +CPPDEFINES_MOD += ['USE_SVC_SHUTDOWN'] + +if FEATURE_FLAGS["RDI"]: + CPPDEFINES_MOD += ['RDI'] + +if FEATURE_FLAGS["SYSTEM_VIEW"]: + SOURCE_FIRMWARE += [ + 'embed/segger/SEGGER/SEGGER_SYSVIEW_Config_NoOS.c', + 'embed/segger/SEGGER/SEGGER_SYSVIEW.c', + 'embed/segger/SEGGER/SEGGER_RTT.c', + 'embed/segger/SEGGER/SEGGER_RTT_ASM_ARMv7M.S', + 'embed/segger/SEGGER/Syscalls/SEGGER_RTT_Syscalls_GCC.c', + 'embed/firmware/systemview.c', + ] + CPPPATH_MOD += [ + 'embed/segger/SEGGER/', + 'embed/segger/Config/', + ] + CPPDEFINES_MOD += ['SYSTEM_VIEW'] + CCFLAGS_MOD += '-DSYSTEM_VIEW ' + +TRANSLATION_DATA = [ + "translations/en.json", + "translations/order.json", +] + +if THP: + CPPDEFINES_MOD += ['USE_THP'] + SOURCE_MOD += [ + 'vendor/trezor-crypto/elligator2.c', + ] + + +env = Environment( + ENV=os.environ, + CFLAGS=f"{ARGUMENTS.get('CFLAGS', '')} -DPRODUCTION={int(PRODUCTION)} -DPYOPT={PYOPT} -DBOOTLOADER_QA={int(BOOTLOADER_QA)} -DBITCOIN_ONLY={BITCOIN_ONLY}", + CPPDEFINES_IMPLICIT=[] + ) + +FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) + +FILE_SUFFIX= env.get('ENV')['SUFFIX'] + +SOURCE_FIRMWARE = [ + 'embed/kernel/main.c', + f'embed/trezorhal/{FILE_SUFFIX}/startup_stage_2.s', +] + +if 'sd_card' in FEATURES_AVAILABLE: + SDCARD = True +else: + SDCARD = False + +env.Replace( + CAT='cat', + DD='dd', + CP='cp', + SED='sed', + AS='arm-none-eabi-as', + AR='arm-none-eabi-ar', + CC='arm-none-eabi-gcc', + LINK='arm-none-eabi-gcc', + SIZE='arm-none-eabi-size', + STRIP='arm-none-eabi-strip', + OBJCOPY='arm-none-eabi-objcopy', ) + +env.Replace( + TREZOR_MODEL=TREZOR_MODEL,) + +ALLPATHS = [ + '.', + 'embed/firmware', + 'embed/lib', + 'embed/models', + 'embed/trezorhal', + ] + CPPPATH_MOD + PATH_HAL + +env.Replace( + COPT=env.get('ENV').get('OPTIMIZE', '-Os'), + CCFLAGS='$COPT ' + '-g3 ' + '-nostdlib ' + '-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' + '-fsingle-precision-constant -fdata-sections -ffunction-sections ' + '-ffreestanding ' + '-fstack-protector-all ' + + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, + LINKFLAGS='-T build/kernel/memory.ld -Wl,--gc-sections -Wl,--print-memory-usage -Wl,-Map=build/kernel/kernel.map -Wl,--warn-common', + CPPPATH=ALLPATHS, + CPPDEFINES=[ + 'KERNEL', + 'TREZOR_MODEL_'+TREZOR_MODEL, + 'USE_HAL_DRIVER', + 'ARM_USER_MODE', + ] + CPPDEFINES_MOD + CPPDEFINES_HAL, + ASFLAGS=env.get('ENV')['CPU_ASFLAGS'], + ASPPFLAGS='$CFLAGS $CCFLAGS', + ) + +env.Replace( + HEADERTOOL='headertool', + PYTHON='python', + MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py', +) + + +# +# Program objects +# + +source_files = SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_FIRMWARE + SOURCE_HAL +obj_program = [] +obj_program.extend(env.Object(source=SOURCE_MOD)) +obj_program.extend(env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero')) +if FEATURE_FLAGS["SECP256K1_ZKP"]: + obj_program.extend(env.Object(source=SOURCE_MOD_SECP256K1_ZKP, CCFLAGS='$CCFLAGS -Wno-unused-function')) + source_files.extend(SOURCE_MOD_SECP256K1_ZKP) +obj_program.extend(env.Object(source=SOURCE_FIRMWARE)) +obj_program.extend(env.Object(source=SOURCE_HAL)) + +env.Replace( + ALLSOURCES=source_files, + ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'] + [f"PRODUCTION={int(PRODUCTION)}", f"BOOTLOADER_QA={int(BOOTLOADER_QA)}", f"PYOPT={PYOPT}", f"BITCOIN_ONLY={BITCOIN_ONLY}"])) + + +cmake_gen = env.Command( + target='CMakeLists.txt', + source='', + action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS', +) + +MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL) +BOOTLOADER_SUFFIX = MODEL_IDENTIFIER +if BOOTLOADER_QA: + BOOTLOADER_SUFFIX += '_qa' + +# select vendor header +if BOOTLOADER_QA or BOOTLOADER_DEVEL: + vendor = "dev_DO_NOT_SIGN_signed_dev" +elif not PRODUCTION: + vendor = "unsafe_signed_prod" +else: + if TREZOR_MODEL in ('T',): + vendor = "satoshilabs_signed_prod" + elif BITCOIN_ONLY == '1': + vendor = "trezor_btconly_signed_prod" + else: + vendor = "trezor_signed_prod" + +VENDORHEADER = f'embed/models/{MODEL_IDENTIFIER}/vendorheader/vendorheader_{vendor}.bin' + + +obj_program.extend( + env.Command( + target='embed/kernel/vendorheader.o', + source=VENDORHEADER, + action='$OBJCOPY -I binary -O elf32-littlearm -B arm' + ' --rename-section .data=.vendorheader,alloc,load,readonly,contents' + ' $SOURCE $TARGET', )) + +if TREZOR_MODEL not in ('DISC1', 'DISC2'): + tools.embed_compressed_binary( + obj_program, + env, + 'bootloader', + 'embed/bootloaders/bootloader.o', + f'embed/models/{MODEL_IDENTIFIER}/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin', + 'kernel' + ) + +linkerscript_gen = env.Command( + target='memory.ld', + source=[f'embed/models/{MODEL_IDENTIFIER}/memory.ld', env.get('ENV')['LINKER_SCRIPT'].format(target='kernel')], + action='$CAT $SOURCES > $TARGET', +) + +program_elf = env.Command( + target='kernel.elf', + source=obj_program, + action= + '$LINK -o $TARGET $CCFLAGS $CFLAGS $SOURCES $LINKFLAGS -lc_nano -lm -lgcc', +) + +env.Depends(program_elf, linkerscript_gen) + +if CMAKELISTS != 0: + env.Depends(program_elf, cmake_gen) + +BINARY_NAME = f"build/kernel/kernel-{models.get_model_identifier(TREZOR_MODEL)}" +if not EVERYTHING: + BINARY_NAME += "-btconly" +BINARY_NAME += "-" + tools.get_version('embed/kernel/version.h') +BINARY_NAME += "-" + tools.get_git_revision_short_hash() +BINARY_NAME += "-dirty" if tools.get_git_modified() else "" +BINARY_NAME += ".bin" + +action_bin=[ + '$OBJCOPY -O binary -j .flash -j .uflash -j .data -j .confidential $SOURCE ${TARGET}', + '$CP $TARGET ' + BINARY_NAME, +] + +program_bin = env.Command( + target='kernel.bin', + source=program_elf, + action=action_bin, +) diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index 91c9f5bf2b5..de09bae4b3a 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -29,6 +29,7 @@ if NEW_RENDERING: CCFLAGS_MOD = '' CPPPATH_MOD = [] CPPDEFINES_MOD = [ + 'KERNEL_MODE', 'AES_128', 'USE_INSECURE_PRNG', ] @@ -114,6 +115,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/qr-code-generator/qrcodegen.c', 'embed/lib/terminal.c', 'vendor/micropython/lib/uzlib/adler32.c', @@ -151,11 +153,10 @@ env = Environment( FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, 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', + f'embed/trezorhal/{FILE_SUFFIX}/startup_stage_2.s', 'embed/prodtest/header.S', 'embed/prodtest/main.c', 'embed/prodtest/prodtest_common.c', @@ -167,6 +168,7 @@ if 'optiga' in FEATURES_AVAILABLE: ] env.Replace( + CAT='cat', CP='cp', AS='arm-none-eabi-as', AR='arm-none-eabi-ar', @@ -192,7 +194,7 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS=f'-T embed/prodtest/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/prodtest/prodtest.map -Wl,--warn-common', + LINKFLAGS=f'-T build/prodtest/memory.ld -Wl,--gc-sections -Wl,-Map=build/prodtest/prodtest.map -Wl,--warn-common', CPPPATH=[ 'embed/prodtest', 'embed/lib', @@ -264,6 +266,12 @@ obj_program.extend( ' --rename-section .data=.vendorheader,alloc,load,readonly,contents' ' $SOURCE $TARGET', )) +linkerscript_gen = env.Command( + target='memory.ld', + source=[f'embed/models/{MODEL_IDENTIFIER}/memory.ld', env.get('ENV')['LINKER_SCRIPT'].format(target='prodtest')], + action='$CAT $SOURCES > $TARGET', +) + program_elf = env.Command( target='prodtest.elf', source=obj_program, @@ -271,6 +279,8 @@ program_elf = env.Command( '$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES -lc_nano -lgcc', ) +env.Depends(program_elf, linkerscript_gen) + BINARY_NAME = f"build/prodtest/prodtest-{models.get_model_identifier(TREZOR_MODEL)}" BINARY_NAME += "-" + tools.get_version('embed/prodtest/version.h') BINARY_NAME += "-" + tools.get_git_revision_short_hash() diff --git a/core/SConscript.reflash b/core/SConscript.reflash index 1567744f8fa..0a1b3e1ce70 100644 --- a/core/SConscript.reflash +++ b/core/SConscript.reflash @@ -61,6 +61,10 @@ elif TREZOR_MODEL in ('T3T1',): FONT_BOLD_UPPER=None FONT_SUB=None +CPPDEFINES_MOD += [ + 'KERNEL_MODE', +] + # modtrezorcrypto CPPPATH_MOD += [ 'vendor/trezor-crypto', @@ -86,6 +90,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_rgba8888.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', @@ -117,22 +122,21 @@ tools.add_font('SUB', FONT_SUB, CPPDEFINES_MOD, SOURCE_MOD) env = Environment( ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), - CONSTRAINTS=["limited_util_s"], CPPDEFINES_IMPLICIT=[] ) FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, 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', + f'embed/trezorhal/{FILE_SUFFIX}/startup_stage_2.s', 'embed/reflash/header.S', 'embed/reflash/main.c', ] env.Replace( + CAT='cat', CP='cp', AS='arm-none-eabi-as', AR='arm-none-eabi-ar', @@ -158,7 +162,7 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS=f'-T embed/reflash/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/reflash/reflash.map -Wl,--warn-common', + LINKFLAGS=f'-T build/reflash/memory.ld -Wl,--gc-sections -Wl,-Map=build/reflash/reflash.map -Wl,--warn-common', CPPPATH=[ 'embed/reflash', 'embed/lib', @@ -210,6 +214,12 @@ obj_program.extend( ' --rename-section .data=.vendorheader,alloc,load,readonly,contents' ' $SOURCE $TARGET', )) +linkerscript_gen = env.Command( + target='memory.ld', + source=[f'embed/models/{MODEL_IDENTIFIER}/memory.ld', env.get('ENV')['LINKER_SCRIPT'].format(target='prodtest')], + action='$CAT $SOURCES > $TARGET', +) + program_elf = env.Command( target='reflash.elf', source=obj_program, @@ -217,6 +227,8 @@ program_elf = env.Command( '$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES -lc_nano -lgcc', ) +env.Depends(program_elf, linkerscript_gen) + BINARY_NAME = f"build/reflash/reflash-{models.get_model_identifier(TREZOR_MODEL)}" BINARY_NAME += "-" + tools.get_version('embed/reflash/version.h') BINARY_NAME += "-" + tools.get_git_revision_short_hash() diff --git a/core/SConscript.unix b/core/SConscript.unix index 4539e800d42..f2071181b0b 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -94,6 +94,7 @@ CPPPATH_MOD += [ 'vendor/trezor-crypto', ] CPPDEFINES_MOD += [ + 'KERNEL_MODE', 'AES_128', 'AES_192', 'USE_INSECURE_PRNG', @@ -242,6 +243,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'embed/lib/translations.c', 'embed/lib/unit_variant.c', @@ -418,12 +420,18 @@ SOURCE_MICROPYTHON = [ ] SOURCE_UNIX = [ - 'embed/trezorhal/unix/boot_args.c', + 'embed/trezorhal/unix/bootutils.c', 'embed/trezorhal/unix/common.c', + 'embed/trezorhal/unix/entropy.c', 'embed/trezorhal/unix/flash_otp.c', 'embed/trezorhal/unix/flash.c', + 'embed/trezorhal/unix/fwutils.c', + 'embed/trezorhal/unix/mpu.c', 'embed/trezorhal/unix/random_delays.c', 'embed/trezorhal/unix/rng.c', + 'embed/trezorhal/unix/system.c', + 'embed/trezorhal/unix/systick.c', + 'embed/trezorhal/unix/systimer.c', 'embed/trezorhal/unix/time_estimate.c', 'embed/trezorhal/unix/usb.c', 'embed/unix/main_main.c', @@ -897,8 +905,9 @@ def cargo_build(): env.get('ENV')['TREZOR_MODEL'] = TREZOR_MODEL bindgen_macros = tools.get_bindgen_defines(env.get("CPPDEFINES"), ALLPATHS) + build_dir = str(Dir('.').abspath) - return f'export BINDGEN_MACROS=\'{bindgen_macros}\'; cd embed/rust; cargo build --profile {RUST_PROFILE} --target-dir=../../build/unix/rust --no-default-features --features "{" ".join(features)}" --target {TARGET}' + return f'export BINDGEN_MACROS=\'{bindgen_macros}\'; export BUILD_DIR=\'{build_dir}\'; cd embed/rust; cargo build --profile {RUST_PROFILE} --target-dir=../../build/unix/rust --no-default-features --features "{" ".join(features)}" --target {TARGET}' rust = env.Command( target=RUST_LIBPATH, diff --git a/core/SConstruct b/core/SConstruct index d4c5aae455b..6446691cf3e 100644 --- a/core/SConstruct +++ b/core/SConstruct @@ -7,6 +7,7 @@ SConscript('SConscript.boardloader', variant_dir='build/boardloader', duplicate= SConscript('SConscript.bootloader', variant_dir='build/bootloader', duplicate=False) SConscript('SConscript.bootloader_ci', variant_dir='build/bootloader_ci', duplicate=False) SConscript('SConscript.bootloader_emu', variant_dir='build/bootloader_emu', duplicate=False) +SConscript('SConscript.kernel', variant_dir='build/kernel', duplicate=False) SConscript('SConscript.firmware', variant_dir='build/firmware', duplicate=False) SConscript('SConscript.prodtest', variant_dir='build/prodtest', duplicate=False) SConscript('SConscript.reflash', variant_dir='build/reflash', duplicate=False) diff --git a/core/embed/boardloader/main.c b/core/embed/boardloader/main.c index 6444fff90d2..a5cb8c15954 100644 --- a/core/embed/boardloader/main.c +++ b/core/embed/boardloader/main.c @@ -21,17 +21,20 @@ #include TREZOR_BOARD #include "board_capabilities.h" +#include "bootutils.h" #include "buffers.h" #include "common.h" #include "compiler_traits.h" #include "display.h" #include "display_draw.h" -#include "fault_handlers.h" #include "flash.h" +#include "flash_utils.h" #include "image.h" #include "model.h" #include "mpu.h" #include "rng.h" +#include "rsod.h" +#include "system.h" #include "terminal.h" #ifdef USE_SD_CARD @@ -207,7 +210,7 @@ static secbool copy_sdcard(void) { term_printf("\n\nerasing flash:\n\n"); // erase all flash (except boardloader) - if (sectrue != flash_area_erase(&ALL_WIPE_AREA, progress_callback)) { + if (sectrue != erase_device(progress_callback)) { term_printf(" failed\n"); return secfalse; } @@ -232,6 +235,8 @@ static secbool copy_sdcard(void) { #endif int main(void) { + system_init(&rsod_panic_handler); + reset_flags_reset(); // need the systick timer running before many HAL operations. @@ -240,9 +245,7 @@ int main(void) { if (sectrue != flash_configure_option_bytes()) { // display is not initialized so don't call ensure - const secbool r = - flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL); - (void)r; + erase_storage(NULL); return 2; } @@ -258,10 +261,6 @@ int main(void) { clear_otg_hs_memory(); #endif - mpu_config_boardloader(); - - fault_handlers_init(); - #ifdef USE_SDRAM sdram_init(); #endif @@ -274,7 +273,8 @@ int main(void) { dma2d_init(); #endif - display_init(); + display_init(DISPLAY_RESET_CONTENT); + display_clear(); display_refresh(); @@ -324,9 +324,13 @@ int main(void) { // This includes the version of bootloader potentially updated from SD card. write_bootloader_min_version(hdr->monotonic); + display_deinit(DISPLAY_JUMP_BEHAVIOR); + +#ifdef ENSURE_COMPATIBLE_SETTINGS ensure_compatible_settings(); +#endif - mpu_config_off(); + mpu_reconfig(MPU_MODE_DISABLED); // g_boot_command is preserved on STM32U5 jump_to(IMAGE_CODE_ALIGN(BOOTLOADER_START + IMAGE_HEADER_SIZE)); diff --git a/core/embed/boardloader/memory_stm32u58.ld b/core/embed/boardloader/memory_stm32u58.ld deleted file mode 100644 index b92fcf30372..00000000000 --- a/core/embed/boardloader/memory_stm32u58.ld +++ /dev/null @@ -1,110 +0,0 @@ -/* Trezor v2 boardloader linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x0C004000, LENGTH = 48K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 - SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K - SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K - SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ - SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ - SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K -} - -main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ -_sstack = ORIGIN(SRAM2); -_estack = main_stack_base; - -/* used by the startup code to populate variables used by the C code */ -data_lma = LOADADDR(.data); -data_vma = ADDR(.data); -data_size = SIZEOF(.data); - -/* used by the startup code to populate variables used by the C code */ -confidential_lma = LOADADDR(.confidential); -confidential_vma = ADDR(.confidential); -confidential_size = SIZEOF(.confidential); - -/* used by the startup code to wipe memory */ -sram1_start = ORIGIN(SRAM1); -sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); -sram2_start = ORIGIN(SRAM2); -sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); -sram3_start = ORIGIN(SRAM3); -sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); -sram4_start = ORIGIN(SRAM4); -sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); -sram5_start = ORIGIN(SRAM5); -sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); -sram6_start = ORIGIN(SRAM6); -sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); - -/* reserve 256 bytes for bootloader arguments */ -boot_args_start = ORIGIN(BOOT_ARGS); -boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); - -SECTIONS { - .vector_table : ALIGN(512) { - KEEP(*(.vector_table)); - } >FLASH AT>FLASH - - .text : ALIGN(4) { - *(.text*); - . = ALIGN(4); /* make the section size a multiple of the word size */ - } >FLASH AT>FLASH - - .rodata : ALIGN(4) { - *(.rodata*); - . = ALIGN(4); /* make the section size a multiple of the word size */ - } >FLASH AT>FLASH - - .data : ALIGN(4) { - *(.data*); - . = ALIGN(8); - } >SRAM1 AT>FLASH - - /DISCARD/ : { - *(.ARM.exidx*); - } - - .bss : ALIGN(4) { - *(.bss*); - . = ALIGN(4); - } >SRAM1 - - .buf : ALIGN(4) { - *(.buf*); - . = ALIGN(4); - } >SRAM1 - - .stack : ALIGN(8) { - . = 16K; /* Overflow causes UsageFault */ - } >SRAM2 - - .confidential : ALIGN(8) { - *(.confidential*); - . = ALIGN(4); - } >SRAM2 AT>FLASH - - .fb : ALIGN(4) { - __fb_start = .; - *(.fb1*); - *(.fb2*); - *(.framebuffer_select*); - __fb_end = .; - . = ALIGN(4); - } >SRAM3 - - .boot_args : ALIGN(8) { - *(.boot_command*); - . = ALIGN(8); - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS - - - /* Hard-coded address for capabilities structure */ - .capabilities 0x0C00FF00 : {KEEP(*(.capabilities_section))} -} diff --git a/core/embed/boardloader/memory_stm32u5a.ld b/core/embed/boardloader/memory_stm32u5a.ld deleted file mode 100644 index f91099d0068..00000000000 --- a/core/embed/boardloader/memory_stm32u5a.ld +++ /dev/null @@ -1,115 +0,0 @@ -/* Trezor v2 boardloader linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x0C004000, LENGTH = 48K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 - 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); -_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 */ -confidential_lma = LOADADDR(.confidential); -confidential_vma = ADDR(.confidential); -confidential_size = SIZEOF(.confidential); - -/* used by the startup code to wipe memory */ -sram1_start = ORIGIN(SRAM1); -sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); -sram2_start = ORIGIN(SRAM2); -sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); -sram3_start = ORIGIN(SRAM3); -sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); -sram4_start = ORIGIN(SRAM4); -sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); -sram5_start = ORIGIN(SRAM5); -sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); -sram6_start = ORIGIN(SRAM6); -sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); - -/* reserve 256 bytes for bootloader arguments */ -boot_args_start = ORIGIN(BOOT_ARGS); -boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); - -SECTIONS { - .vector_table : ALIGN(1024) { - KEEP(*(.vector_table)); - } >FLASH AT>FLASH - - .text : ALIGN(4) { - *(.text*); - . = ALIGN(4); /* make the section size a multiple of the word size */ - } >FLASH AT>FLASH - - .rodata : ALIGN(4) { - *(.rodata*); - . = ALIGN(4); /* make the section size a multiple of the word size */ - } >FLASH AT>FLASH - - .data : ALIGN(4) { - *(.data*); - . = ALIGN(8); - } >SRAM1 AT>FLASH - - /DISCARD/ : { - *(.ARM.exidx*); - } - - .bss : ALIGN(4) { - *(.bss*); - . = ALIGN(4); - } >SRAM1 - - .buf : ALIGN(4) { - *(.buf*); - . = ALIGN(4); - } >SRAM1 - - .stack : ALIGN(8) { - . = 16K; /* Overflow causes UsageFault */ - } >SRAM2 - - .confidential : ALIGN(8) { - *(.confidential*); - . = 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 - - .boot_args : ALIGN(8) { - *(.boot_command*); - . = ALIGN(8); - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS - - - /* Hard-coded address for capabilities structure */ - .capabilities 0x0C00FF00 : {KEEP(*(.capabilities_section))} -} diff --git a/core/embed/boardloader/startup_stm32u5.s b/core/embed/boardloader/startup_stm32u5.s deleted file mode 100644 index fc30e4b6377..00000000000 --- a/core/embed/boardloader/startup_stm32u5.s +++ /dev/null @@ -1,107 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // set the stack protection - ldr r0, =_sstack - add r0, r0, #16 // padding - msr MSPLIM, r0 - - bl SystemInit - - // read the first rng data and save it - ldr r0, =0 // r0 - previous value - ldr r1, =0 // r1 - whether to compare the previous value - bl rng_read - - // read the next rng data and make sure it is different than previous - // r0 - value returned from previous call - ldr r1, =1 // r1 - whether to compare the previous value - bl rng_read - mov r4, r0 // save TRNG output in r4 - - // wipe memory to remove any possible vestiges of confidential 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 confidential data in from flash - ldr r0, =confidential_vma // dst addr - ldr r1, =confidential_lma // src addr - ldr r2, =confidential_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/emulator.c b/core/embed/bootloader/emulator.c index fb570b0c9b8..99d2dd8611b 100644 --- a/core/embed/bootloader/emulator.c +++ b/core/embed/bootloader/emulator.c @@ -2,7 +2,7 @@ #include #include TREZOR_BOARD -#include "boot_args.h" +#include "bootargs.h" #include "bootui.h" #include "common.h" #include "display.h" @@ -92,7 +92,7 @@ bool load_firmware(const char *filename, uint8_t *hash) { } __attribute__((noreturn)) int main(int argc, char **argv) { - display_init(); + display_init(DISPLAY_RESET_CONTENT); flash_init(); flash_otp_init(); @@ -170,11 +170,7 @@ __attribute__((noreturn)) int main(int argc, char **argv) { jump_to(0); } -void mpu_config_bootloader(void) {} - -void mpu_config_off(void) {} - -__attribute__((noreturn)) void jump_to(uint32_t address) { +void jump_to(uint32_t address) { bool storage_is_erased = storage_empty(&STORAGE_AREAS[0]) && storage_empty(&STORAGE_AREAS[1]); @@ -188,5 +184,3 @@ __attribute__((noreturn)) void jump_to(uint32_t address) { "STORAGE WAS RETAINED"); } } - -void ensure_compatible_settings(void) {} diff --git a/core/embed/bootloader/emulator.h b/core/embed/bootloader/emulator.h index 9facab471ce..7cd1adb01a7 100644 --- a/core/embed/bootloader/emulator.h +++ b/core/embed/bootloader/emulator.h @@ -13,10 +13,6 @@ extern uint8_t *FIRMWARE_START; void emulator_poll_events(void); void set_core_clock(int); -void mpu_config_bootloader(void); -void mpu_config_off(void); -void display_set_little_endian(void); -void jump_to(uint32_t address); -void ensure_compatible_settings(void); +__attribute__((noreturn)) void jump_to(uint32_t address); #endif diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index 211916c682e..73c05962bbc 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -20,19 +20,23 @@ #include #include -#include "boot_args.h" +#include "bootargs.h" +#include "bootutils.h" #include "common.h" #include "display.h" #include "display_utils.h" -#include "fault_handlers.h" #include "flash.h" #include "flash_otp.h" +#include "flash_utils.h" #include "image.h" #include "lowlevel.h" #include "messages.pb.h" #include "random_delays.h" +#include "rsod.h" #include "secbool.h" #include "secret.h" +#include "system.h" +#include "systimer.h" #ifdef USE_DMA2D #ifdef NEW_RENDERING @@ -41,9 +45,6 @@ #include "dma2d.h" #endif #endif -#ifdef USE_I2C -#include "i2c.h" -#endif #ifdef USE_OPTIGA #include "optiga_hal.h" #endif @@ -62,6 +63,9 @@ #ifdef USE_HASH_PROCESSOR #include "hash_processor.h" #endif +#ifdef STM32U5 +#include "irq.h" +#endif #include "model.h" #include "usb.h" @@ -327,23 +331,22 @@ void real_jump_to_firmware(void) { ui_screen_boot_stage_1(false); } - display_finish_actions(); + display_deinit(DISPLAY_JUMP_BEHAVIOR); + +#ifdef ENSURE_COMPATIBLE_SETTINGS ensure_compatible_settings(); +#endif + + mpu_reconfig(MPU_MODE_DISABLED); - mpu_config_off(); jump_to(IMAGE_CODE_ALIGN(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE)); } #ifdef STM32U5 __attribute__((noreturn)) void jump_to_fw_through_reset(void) { - display_finish_actions(); display_fade(display_backlight(-1), 0, 200); - __disable_irq(); - delete_secrets(); - NVIC_SystemReset(); - for (;;) - ; + reboot(); } #endif @@ -354,7 +357,9 @@ int bootloader_main(void) { #endif secbool stay_in_bootloader = secfalse; - random_delays_init(); + system_init(&rsod_panic_handler); + + rdi_init(); #if defined TREZOR_MODEL_T set_core_clock(CLOCK_180_MHZ); @@ -364,11 +369,7 @@ int bootloader_main(void) { hash_processor_init(); #endif -#ifdef USE_I2C - i2c_init(); -#endif - - display_reinit(); + display_init(DISPLAY_JUMP_BEHAVIOR); #ifdef USE_DMA2D dma2d_init(); @@ -395,10 +396,6 @@ int bootloader_main(void) { ui_screen_boot_stage_1(false); - mpu_config_bootloader(); - - fault_handlers_init(); - #ifdef TREZOR_EMULATOR // wait a bit so that the empty lock icon is visible // (on a real device, we are waiting for touch init which takes longer) @@ -560,9 +557,7 @@ int bootloader_main(void) { #ifdef STM32U5 secret_bhk_regenerate(); #endif - // erase storage - ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), - NULL); + ensure(erase_storage(NULL), NULL); // keep the model screen up for a while #ifndef USE_BACKLIGHT @@ -670,8 +665,7 @@ int bootloader_main(void) { #ifdef STM32U5 secret_bhk_regenerate(); #endif - ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), - NULL); + ensure(erase_storage(NULL), NULL); } ensure(dont_optimize_out_true * (continue_to_firmware == continue_to_firmware_backup), diff --git a/core/embed/bootloader/memory_stm32f4.ld b/core/embed/bootloader/memory_stm32f4.ld deleted file mode 100644 index 392c9a1d8e2..00000000000 --- a/core/embed/bootloader/memory_stm32f4.ld +++ /dev/null @@ -1,79 +0,0 @@ -/* Trezor v2 bootloader linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 128K - CCMRAM (wal) : ORIGIN = 0x10000000, LENGTH = 64K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x1000FF00, LENGTH = 0x100 - SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 192K -} - -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); -data_vma = ADDR(.data); -data_size = SIZEOF(.data); - -/* used by the startup code to wipe memory */ -ccmram_start = ORIGIN(CCMRAM); -ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); - -/* used by the startup code to wipe memory */ -sram_start = ORIGIN(SRAM); -sram_end = ORIGIN(SRAM) + LENGTH(SRAM); - -/* reserve 256 bytes for bootloader arguments */ -boot_args_start = ORIGIN(BOOT_ARGS); -boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); - -_codelen = SIZEOF(.flash) + SIZEOF(.data); - -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 - - .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 - - .buf : ALIGN(4) { - *(.buf*); - . = ALIGN(4); - *(.no_dma_buffers*); - . = ALIGN(4); - } >SRAM - - .boot_args : ALIGN(8) { - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS - -} diff --git a/core/embed/bootloader/memory_stm32u5a.ld b/core/embed/bootloader/memory_stm32u5a.ld deleted file mode 100644 index e34a7d53e19..00000000000 --- a/core/embed/bootloader/memory_stm32u5a.ld +++ /dev/null @@ -1,114 +0,0 @@ -/* Trezor v2 bootloader linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x0C010000, LENGTH = 128K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 - 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); -_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 */ -confidential_lma = LOADADDR(.confidential); -confidential_vma = ADDR(.confidential); -confidential_size = SIZEOF(.confidential); - -/* 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); - -_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); - -SECTIONS { - .header : ALIGN(4) { - KEEP(*(.header)); - } >FLASH AT>FLASH - - .flash : ALIGN(1024) { - 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); - *(.no_dma_buffers*); - . = ALIGN(4); - } >SRAM1 - - .stack : ALIGN(8) { - . = 16K; /* Overflow causes UsageFault */ - } >SRAM2 - - .confidential : ALIGN(512) { - *(.confidential*); - . = 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 - - .boot_args : ALIGN(8) { - *(.boot_command*); - . = ALIGN(8); - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS -} diff --git a/core/embed/bootloader/messages.c b/core/embed/bootloader/messages.c index 5006afb856f..e5c16ce75b0 100644 --- a/core/embed/bootloader/messages.c +++ b/core/embed/bootloader/messages.c @@ -24,9 +24,10 @@ #include #include "messages.pb.h" -#include "boot_args.h" +#include "bootargs.h" #include "common.h" #include "flash.h" +#include "flash_utils.h" #include "image.h" #include "secbool.h" #include "secret.h" @@ -715,8 +716,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, #ifdef STM32U5 secret_bhk_regenerate(); #endif - ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), - NULL); + ensure(erase_storage(NULL), NULL); } headers_offset = IMAGE_CODE_ALIGN(IMAGE_HEADER_SIZE + vhdr.hdrlen); @@ -840,7 +840,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, } secbool bootloader_WipeDevice(void) { - return flash_area_erase(&WIPE_AREA, ui_screen_wipe_progress); + return erase_device(ui_screen_wipe_progress); } int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { diff --git a/core/embed/bootloader_ci/main.c b/core/embed/bootloader_ci/main.c index 6d7565dcc30..b43e06a6c52 100644 --- a/core/embed/bootloader_ci/main.c +++ b/core/embed/bootloader_ci/main.c @@ -20,6 +20,7 @@ #include #include +#include "bootutils.h" #include "common.h" #include "display.h" #include "display_draw.h" @@ -30,7 +31,9 @@ #include "mpu.h" #include "random_delays.h" #include "rng.h" +#include "rsod.h" #include "secbool.h" +#include "system.h" #ifdef USE_TOUCH #include "touch.h" #endif @@ -176,7 +179,9 @@ static secbool check_vendor_header_lock(const vendor_header *const vhdr) { } int main(void) { - random_delays_init(); + system_init(&rsod_panic_handler); + + rdi_init(); #ifdef USE_TOUCH touch_init(); #endif @@ -185,8 +190,6 @@ int main(void) { hash_processor_init(); #endif - mpu_config_bootloader(); - #if PRODUCTION && !defined STM32U5 // for STM32U5, this check is moved to boardloader ensure_bootloader_min_version(); @@ -267,7 +270,8 @@ int main(void) { // do not check any trust flags on header, proceed - mpu_config_off(); + mpu_reconfig(MPU_MODE_DISABLED); + jump_to(IMAGE_CODE_ALIGN(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE)); return 0; diff --git a/core/embed/bootloader_ci/memory_stm32u58.ld b/core/embed/bootloader_ci/memory_stm32u58.ld deleted file mode 100644 index 876807cb8c6..00000000000 --- a/core/embed/bootloader_ci/memory_stm32u58.ld +++ /dev/null @@ -1,106 +0,0 @@ -/* Trezor v2 bootloader linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x0C010000, LENGTH = 128K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 - SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K - SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K - SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ - SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ - SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K -} - -main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ -_sstack = ORIGIN(SRAM2); -_estack = main_stack_base; - -/* used by the startup code to populate variables used by the C code */ -data_lma = LOADADDR(.data); -data_vma = ADDR(.data); -data_size = SIZEOF(.data); - -/* used by the startup code to populate variables used by the C code */ -confidential_lma = LOADADDR(.confidential); -confidential_vma = ADDR(.confidential); -confidential_size = SIZEOF(.confidential); - -/* 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); - -_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); - -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; /* Exactly 16K allocated for stack. Overflow causes Usage fault. */ - } >SRAM2 - - .confidential : ALIGN(512) { - *(.confidential*); - . = ALIGN(512); - } >SRAM2 AT>FLASH - - .fb : ALIGN(4) { - __fb_start = .; - *(.fb1*); - *(.fb2*); - __fb_end = .; - . = ALIGN(4); - } >SRAM3 - - .boot_args : ALIGN(8) { - *(.boot_command*); - . = ALIGN(8); - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS -} diff --git a/core/embed/bootloader_ci/memory_stm32u5a.ld b/core/embed/bootloader_ci/memory_stm32u5a.ld deleted file mode 100644 index accf7658614..00000000000 --- a/core/embed/bootloader_ci/memory_stm32u5a.ld +++ /dev/null @@ -1,112 +0,0 @@ -/* Trezor v2 bootloader linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x0C010000, LENGTH = 128K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 - 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); -_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 */ -confidential_lma = LOADADDR(.confidential); -confidential_vma = ADDR(.confidential); -confidential_size = SIZEOF(.confidential); - -/* 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); - -_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); - -SECTIONS { - .header : ALIGN(4) { - KEEP(*(.header)); - } >FLASH AT>FLASH - - .flash : ALIGN(1024) { - 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; /* Overflow causes UsageFault */ - } >SRAM2 - - .confidential : ALIGN(512) { - *(.confidential*); - . = 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 - - .boot_args : ALIGN(8) { - *(.boot_command*); - . = ALIGN(8); - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS -} diff --git a/core/embed/bootloader_ci/messages.c b/core/embed/bootloader_ci/messages.c index ee177017a13..8303a998528 100644 --- a/core/embed/bootloader_ci/messages.c +++ b/core/embed/bootloader_ci/messages.c @@ -26,6 +26,7 @@ #include "common.h" #include "flash.h" +#include "flash_utils.h" #include "image.h" #include "model.h" #include "secbool.h" @@ -648,14 +649,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, } int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { - flash_area_t wipe_area[STORAGE_AREAS_COUNT + 1]; - for (int i = 0; i < STORAGE_AREAS_COUNT; i++) { - memcpy(&wipe_area[i], &STORAGE_AREAS[i], sizeof(flash_area_t)); - } - memcpy(&wipe_area[STORAGE_AREAS_COUNT], &FIRMWARE_AREA, sizeof(flash_area_t)); - - if (sectrue != flash_area_erase_bulk(wipe_area, STORAGE_AREAS_COUNT + 1, - ui_screen_wipe_progress)) { + if (sectrue != erase_device(ui_screen_wipe_progress)) { MSG_SEND_INIT(Failure); MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); MSG_SEND_ASSIGN_STRING(message, "Could not erase flash"); diff --git a/core/embed/bootloader_ci/startup_stm32u5.s b/core/embed/bootloader_ci/startup_stm32u5.s deleted file mode 100644 index ab5b61495d4..00000000000 --- a/core/embed/bootloader_ci/startup_stm32u5.s +++ /dev/null @@ -1,68 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // set the stack protection - ldr r0, =_sstack - add r0, r0, #16 // padding - msr MSPLIM, r0 - - // 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 confidential data in from flash - ldr r0, =confidential_vma // dst addr - ldr r1, =confidential_lma // src addr - ldr r2, =confidential_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/extmod/modtrezorconfig/modtrezorconfig.c b/core/embed/extmod/modtrezorconfig/modtrezorconfig.c index 8bd5212e6db..10df09495ea 100644 --- a/core/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/core/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -28,6 +28,7 @@ #include "embed/extmod/trezorobj.h" #include "common.h" +#include "entropy.h" #include "memzero.h" #include "storage.h" @@ -55,13 +56,16 @@ static secbool wrapped_ui_wait_callback(uint32_t wait, uint32_t progress, /// called from this module! /// """ STATIC mp_obj_t mod_trezorconfig_init(size_t n_args, const mp_obj_t *args) { + uint8_t entropy_data[HW_ENTROPY_LEN]; + entropy_get(entropy_data); + if (n_args > 0) { MP_STATE_VM(trezorconfig_ui_wait_callback) = args[0]; - storage_init(wrapped_ui_wait_callback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); + storage_init(wrapped_ui_wait_callback, entropy_data, HW_ENTROPY_LEN); } else { - storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN); + storage_init(NULL, entropy_data, HW_ENTROPY_LEN); } - memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA)); + memzero(entropy_data, sizeof(entropy_data)); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_init_obj, 0, 1, diff --git a/core/embed/extmod/modtrezorio/modtrezorio-flash.h b/core/embed/extmod/modtrezorio/modtrezorio-flash.h deleted file mode 100644 index 3815f1e7124..00000000000 --- a/core/embed/extmod/modtrezorio/modtrezorio-flash.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 "flash_otp.h" - -#include "embed/extmod/trezorobj.h" - -/// package: trezorio.__init__ - -/// class FlashOTP: -/// """ -/// """ -typedef struct _mp_obj_FlashOTP_t { - mp_obj_base_t base; -} mp_obj_FlashOTP_t; - -/// def __init__(self) -> None: -/// """ -/// """ -STATIC mp_obj_t mod_trezorio_FlashOTP_make_new(const mp_obj_type_t *type, - size_t n_args, size_t n_kw, - const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 0, 0, false); - mp_obj_FlashOTP_t *o = mp_obj_malloc(mp_obj_FlashOTP_t, type); - return MP_OBJ_FROM_PTR(o); -} - -/// def write(self, block: int, offset: int, data: bytes) -> None: -/// """ -/// Writes data to OTP flash -/// """ -STATIC mp_obj_t mod_trezorio_FlashOTP_write(size_t n_args, - const mp_obj_t *args) { - uint8_t block = trezor_obj_get_uint8(args[1]); - uint8_t offset = trezor_obj_get_uint8(args[2]); - mp_buffer_info_t data = {0}; - mp_get_buffer_raise(args[3], &data, MP_BUFFER_READ); - if (sectrue != flash_otp_write(block, offset, data.buf, data.len)) { - mp_raise_ValueError("write failed"); - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_FlashOTP_write_obj, 4, - 4, mod_trezorio_FlashOTP_write); - -/// def read(self, block: int, offset: int, data: bytearray) -> None: -/// """ -/// Reads data from OTP flash -/// """ -STATIC mp_obj_t mod_trezorio_FlashOTP_read(size_t n_args, - const mp_obj_t *args) { - uint8_t block = trezor_obj_get_uint8(args[1]); - uint8_t offset = trezor_obj_get_uint8(args[2]); - mp_buffer_info_t data = {0}; - mp_get_buffer_raise(args[3], &data, MP_BUFFER_WRITE); - if (sectrue != flash_otp_read(block, offset, data.buf, data.len)) { - mp_raise_ValueError("read failed"); - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_FlashOTP_read_obj, 4, 4, - mod_trezorio_FlashOTP_read); - -/// def lock(self, block: int) -> None: -/// """ -/// Lock OTP flash block -/// """ -STATIC mp_obj_t mod_trezorio_FlashOTP_lock(mp_obj_t self, mp_obj_t block) { - uint8_t b = trezor_obj_get_uint8(block); - if (sectrue != flash_otp_lock(b)) { - mp_raise_ValueError("lock failed"); - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FlashOTP_lock_obj, - mod_trezorio_FlashOTP_lock); - -/// def is_locked(self, block: int) -> bool: -/// """ -/// Is OTP flash block locked? -/// """ -STATIC mp_obj_t mod_trezorio_FlashOTP_is_locked(mp_obj_t self, mp_obj_t block) { - uint8_t b = trezor_obj_get_uint8(block); - return (sectrue == flash_otp_is_locked(b)) ? mp_const_true : mp_const_false; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FlashOTP_is_locked_obj, - mod_trezorio_FlashOTP_is_locked); - -STATIC const mp_rom_map_elem_t mod_trezorio_FlashOTP_locals_dict_table[] = { - {MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_trezorio_FlashOTP_read_obj)}, - {MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_FlashOTP_write_obj)}, - {MP_ROM_QSTR(MP_QSTR_lock), MP_ROM_PTR(&mod_trezorio_FlashOTP_lock_obj)}, - {MP_ROM_QSTR(MP_QSTR_is_locked), - MP_ROM_PTR(&mod_trezorio_FlashOTP_is_locked_obj)}, -}; -STATIC MP_DEFINE_CONST_DICT(mod_trezorio_FlashOTP_locals_dict, - mod_trezorio_FlashOTP_locals_dict_table); - -STATIC const mp_obj_type_t mod_trezorio_FlashOTP_type = { - {&mp_type_type}, - .name = MP_QSTR_FlashOTP, - .make_new = mod_trezorio_FlashOTP_make_new, - .locals_dict = (void *)&mod_trezorio_FlashOTP_locals_dict, -}; diff --git a/core/embed/extmod/modtrezorio/modtrezorio-hid.h b/core/embed/extmod/modtrezorio/modtrezorio-hid.h index 9cf38d48948..c5dd5195d3a 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio-hid.h +++ b/core/embed/extmod/modtrezorio/modtrezorio-hid.h @@ -17,6 +17,8 @@ * along with this program. If not, see . */ +#include "embed/extmod/trezorobj.h" + /// package: trezorio.__init__ /// class HID: diff --git a/core/embed/extmod/modtrezorio/modtrezorio-vcp.h b/core/embed/extmod/modtrezorio/modtrezorio-vcp.h index d063ba143d1..fc9ae5261fe 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio-vcp.h +++ b/core/embed/extmod/modtrezorio/modtrezorio-vcp.h @@ -17,8 +17,6 @@ * along with this program. If not, see . */ -void pendsv_kbd_intr(void); - /// package: trezorio.__init__ /// class VCP: @@ -93,7 +91,7 @@ STATIC mp_obj_t mod_trezorio_VCP_make_new(const mp_obj_type_t *type, o->info.rx_buffer = m_new(uint8_t, vcp_buffer_len); o->info.tx_buffer_len = vcp_buffer_len; o->info.rx_buffer_len = vcp_buffer_len; - o->info.rx_intr_fn = pendsv_kbd_intr; + o->info.rx_intr_fn = NULL; o->info.rx_intr_byte = 3; // Ctrl-C o->info.iface_num = (uint8_t)(iface_num); o->info.data_iface_num = (uint8_t)(data_iface_num); diff --git a/core/embed/extmod/modtrezorio/modtrezorio.c b/core/embed/extmod/modtrezorio/modtrezorio.c index a40ae962633..7e63a81d695 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio.c +++ b/core/embed/extmod/modtrezorio/modtrezorio.c @@ -43,7 +43,6 @@ uint32_t last_touch_sample_time = 0; } // clang-format off -#include "modtrezorio-flash.h" #include "modtrezorio-hid.h" #include "modtrezorio-poll.h" #include "modtrezorio-vcp.h" @@ -114,8 +113,6 @@ STATIC const mp_rom_map_elem_t mp_module_trezorio_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_BUTTON_RIGHT), MP_ROM_INT(BTN_RIGHT)}, #endif - {MP_ROM_QSTR(MP_QSTR_FlashOTP), MP_ROM_PTR(&mod_trezorio_FlashOTP_type)}, - {MP_ROM_QSTR(MP_QSTR_USB), MP_ROM_PTR(&mod_trezorio_USB_type)}, {MP_ROM_QSTR(MP_QSTR_HID), MP_ROM_PTR(&mod_trezorio_HID_type)}, {MP_ROM_QSTR(MP_QSTR_VCP), MP_ROM_PTR(&mod_trezorio_VCP_type)}, diff --git a/core/embed/extmod/modtrezorutils/modtrezorutils.c b/core/embed/extmod/modtrezorutils/modtrezorutils.c index d00e35d11ff..c77ed28373d 100644 --- a/core/embed/extmod/modtrezorutils/modtrezorutils.c +++ b/core/embed/extmod/modtrezorutils/modtrezorutils.c @@ -19,9 +19,6 @@ #include "py/objstr.h" #include "py/runtime.h" -#ifndef TREZOR_EMULATOR -#include "supervise.h" -#endif #include "image.h" #include "version.h" @@ -33,25 +30,21 @@ #include #include "blake2s.h" -#include "common.h" -#include "flash.h" +#include "bootutils.h" +#include "error_handling.h" +#include "fwutils.h" #include "unit_variant.h" #include "usb.h" #include TREZOR_BOARD #include "model.h" -#ifndef TREZOR_EMULATOR -#include "image.h" -#endif - #if USE_OPTIGA && !defined(TREZOR_EMULATOR) #include "secret.h" #endif -#define FW_HASHING_CHUNK_SIZE 1024 +static void ui_progress(void *context, uint32_t current, uint32_t total) { + mp_obj_t ui_wait_callback = (mp_obj_t)context; -static void ui_progress(mp_obj_t ui_wait_callback, uint32_t current, - uint32_t total) { if (mp_obj_is_callable(ui_wait_callback)) { mp_call_function_2_protected(ui_wait_callback, mp_obj_new_int(current), mp_obj_new_int(total)); @@ -155,51 +148,23 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_halt_obj, 0, 1, /// """ STATIC mp_obj_t mod_trezorutils_firmware_hash(size_t n_args, const mp_obj_t *args) { - BLAKE2S_CTX ctx; mp_buffer_info_t chal = {0}; if (n_args > 0 && args[0] != mp_const_none) { mp_get_buffer_raise(args[0], &chal, MP_BUFFER_READ); } - if (chal.len != 0) { - if (blake2s_InitKey(&ctx, BLAKE2S_DIGEST_LENGTH, chal.buf, chal.len) != 0) { - mp_raise_msg(&mp_type_ValueError, "Invalid challenge."); - } - } else { - blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); - } - mp_obj_t ui_wait_callback = mp_const_none; if (n_args > 1 && args[1] != mp_const_none) { ui_wait_callback = args[1]; } - uint32_t firmware_size = flash_area_get_size(&FIRMWARE_AREA); - uint32_t chunks = firmware_size / FW_HASHING_CHUNK_SIZE; - - ensure((firmware_size % FW_HASHING_CHUNK_SIZE == 0) * sectrue, - "Cannot compute FW hash."); - - ui_progress(ui_wait_callback, 0, chunks); - for (int i = 0; i < chunks; i++) { - const void *data = flash_area_get_address( - &FIRMWARE_AREA, i * FW_HASHING_CHUNK_SIZE, FW_HASHING_CHUNK_SIZE); - if (data == NULL) { - mp_raise_msg(&mp_type_RuntimeError, "Failed to read firmware."); - } - blake2s_Update(&ctx, data, FW_HASHING_CHUNK_SIZE); - if (i % 128 == 0) { - ui_progress(ui_wait_callback, i + 1, chunks); - } - } - - ui_progress(ui_wait_callback, chunks, chunks); - vstr_t vstr = {0}; vstr_init_len(&vstr, BLAKE2S_DIGEST_LENGTH); - if (blake2s_Final(&ctx, vstr.buf, vstr.len) != 0) { + + if (sectrue != firmware_calc_hash(chal.buf, chal.len, (uint8_t *)vstr.buf, + vstr.len, ui_progress, ui_wait_callback)) { vstr_clear(&vstr); - mp_raise_msg(&mp_type_RuntimeError, "Failed to finalize firmware hash."); + mp_raise_msg(&mp_type_RuntimeError, "Failed to calculate firmware hash."); } return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); @@ -215,13 +180,11 @@ STATIC mp_obj_t mod_trezorutils_firmware_vendor(void) { #ifdef TREZOR_EMULATOR return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)"EMULATOR", 8); #else - vendor_header vhdr = {0}; - const void *data = flash_area_get_address(&FIRMWARE_AREA, 0, 0); - if (data == NULL || sectrue != read_vendor_header(data, &vhdr)) { + char vendor[64] = {0}; + if (sectrue != firmware_get_vendor(vendor, sizeof(vendor))) { mp_raise_msg(&mp_type_RuntimeError, "Failed to read vendor header."); } - return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)vhdr.vstr, - vhdr.vstr_len); + return mp_obj_new_str_copy(&mp_type_str, (byte *)vendor, strlen(vendor)); #endif } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_firmware_vendor_obj, @@ -286,31 +249,37 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_sd_hotswap_enabled_obj, STATIC mp_obj_t mod_trezorutils_reboot_to_bootloader(size_t n_args, const mp_obj_t *args) { #ifndef TREZOR_EMULATOR - boot_command_t boot_command = BOOT_COMMAND_NONE; - mp_buffer_info_t boot_args = {0}; - if (n_args > 0 && args[0] != mp_const_none) { mp_int_t value = mp_obj_get_int(args[0]); switch (value) { case 0: - boot_command = BOOT_COMMAND_STOP_AND_WAIT; + // Reboot and stay in bootloader + reboot_to_bootloader(); break; case 1: - boot_command = BOOT_COMMAND_INSTALL_UPGRADE; + // Reboot and continue with the firmware upgrade + mp_buffer_info_t hash = {0}; + + if (n_args > 1 && args[1] != mp_const_none) { + mp_get_buffer_raise(args[1], &hash, MP_BUFFER_READ); + } + + if (hash.len != 32) { + mp_raise_ValueError("Invalid value."); + } + + reboot_and_upgrade((uint8_t *)hash.buf); break; default: mp_raise_ValueError("Invalid value."); break; } + } else { + // Just reboot and go through the normal boot sequence + reboot(); } - if (n_args > 1 && args[1] != mp_const_none) { - mp_get_buffer_raise(args[1], &boot_args, MP_BUFFER_READ); - } - - bootargs_set(boot_command, boot_args.buf, boot_args.len); - svc_reboot_to_bootloader(); #endif return mp_const_none; } diff --git a/core/embed/firmware/delay.c b/core/embed/firmware/delay.c deleted file mode 100644 index 0c4c267c322..00000000000 --- a/core/embed/firmware/delay.c +++ /dev/null @@ -1,118 +0,0 @@ -// clang-format off - -/* - * 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 . - */ - -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2013, 2014 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/runtime.h" -#include "py/mphal.h" -#include "irq.h" - -extern __IO uint32_t uwTick; - -// We provide our own version of HAL_Delay that calls __WFI while waiting, -// and works when interrupts are disabled. This function is intended to be -// used only by the ST HAL functions. -void HAL_Delay(uint32_t Delay) { - if (query_irq() == IRQ_STATE_ENABLED) { - // IRQs enabled, so can use systick counter to do the delay - uint32_t start = uwTick; - // Wraparound of tick is taken care of by 2's complement arithmetic. - while (uwTick - start < Delay) { - // Enter sleep mode, waiting for (at least) the SysTick interrupt. - __WFI(); - } - } else { - // IRQs disabled, use mp_hal_delay_ms routine. - mp_hal_delay_ms(Delay); - } -} - -// Core delay function that does an efficient sleep and may switch thread context. -// If IRQs are enabled then we must have the GIL. -void mp_hal_delay_ms(mp_uint_t Delay) { - if (query_irq() == IRQ_STATE_ENABLED) { - // IRQs enabled, so can use systick counter to do the delay - uint32_t start = uwTick; - // Wraparound of tick is taken care of by 2's complement arithmetic. - while (uwTick - start < Delay) { - // This macro will execute the necessary idle behaviour. It may - // raise an exception, switch threads or enter sleep mode (waiting for - // (at least) the SysTick interrupt). - MICROPY_EVENT_POLL_HOOK - } - } else { - // IRQs disabled, so need to use a busy loop for the delay. - // To prevent possible overflow of the counter we use a double loop. - const uint32_t count_1ms = HAL_RCC_GetSysClockFreq() / 4000; - for (int i = 0; i < Delay; i++) { - for (uint32_t count = 0; ++count <= count_1ms;) { - } - } - } -} - -// delay for given number of microseconds -void mp_hal_delay_us(mp_uint_t usec) { - if (query_irq() == IRQ_STATE_ENABLED) { - // IRQs enabled, so can use systick counter to do the delay - uint32_t start = mp_hal_ticks_us(); - while (mp_hal_ticks_us() - start < usec) { - } - } else { - // IRQs disabled, so need to use a busy loop for the delay - // sys freq is always a multiple of 2MHz, so division here won't lose precision - const uint32_t ucount = HAL_RCC_GetSysClockFreq() / 2000000 * usec / 2; - for (uint32_t count = 0; ++count <= ucount;) { - } - } -} - -mp_uint_t mp_hal_ticks_ms(void) { - return uwTick; -} - -mp_uint_t mp_hal_ticks_us(void) { - return uwTick * 1000; -} diff --git a/core/embed/firmware/firmware_flash.jlink b/core/embed/firmware/firmware_flash.jlink deleted file mode 100644 index 8292e2f66e9..00000000000 --- a/core/embed/firmware/firmware_flash.jlink +++ /dev/null @@ -1,8 +0,0 @@ -device stm32f427vi -if swd -speed 50000 -loadbin build/firmware/firmware.bin.p1.bin 0x08040000 -loadbin build/firmware/firmware.bin.p2.bin 0x08120000 -r -g -exit diff --git a/core/embed/firmware/firmware_flash_t1.jlink b/core/embed/firmware/firmware_flash_t1.jlink deleted file mode 100644 index 14f786c3ec8..00000000000 --- a/core/embed/firmware/firmware_flash_t1.jlink +++ /dev/null @@ -1,7 +0,0 @@ -device STM32F205RG -if swd -speed 50000 -loadbin build/firmware/firmware.bin 0x08010000 -r -g -exit diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index fc59514d3c6..99c29dba3d6 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -36,220 +36,26 @@ #include "ports/stm32/gccollect.h" #include "ports/stm32/pendsv.h" -#include "bl_check.h" -#include "board_capabilities.h" -#include "common.h" -#include "compiler_traits.h" -#include "display.h" -#include "fault_handlers.h" -#include "flash.h" -#include "image.h" -#include "memzero.h" -#include "model.h" -#include "mpu.h" -#include "random_delays.h" -#include "rust_ui.h" -#include "secure_aes.h" +#include "error_handling.h" +#include "rsod.h" +#include "rust_ui_common.h" +#include "secbool.h" +#include "systask.h" +#include "system.h" -#include TREZOR_BOARD - -#ifdef USE_RGB_LED -#include "rgb_led.h" -#endif -#ifdef USE_CONSUMPTION_MASK -#include "consumption_mask.h" -#endif -#ifdef USE_DMA2D -#ifdef NEW_RENDERING -#include "dma2d_bitblt.h" -#else -#include "dma2d.h" -#endif -#endif - -#ifdef USE_BUTTON -#include "button.h" -#endif -#ifdef USE_I2C -#include "i2c.h" -#endif -#ifdef USE_TOUCH -#include "touch.h" -#endif -#ifdef USE_SD_CARD -#include "sdcard.h" -#endif -#ifdef USE_HASH_PROCESSOR -#include "hash_processor.h" -#endif - -#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 -#include "systemview.h" -#endif -#include "platform.h" -#include "rng.h" -#include "supervise.h" #ifdef USE_SECP256K1_ZKP #include "zkp_context.h" #endif -#ifdef USE_HAPTIC -#include "haptic.h" -#endif - -// from util.s -extern void shutdown_privileged(void); -#ifdef USE_OPTIGA -#if !PYOPT -#include -#if 1 // color log -#define OPTIGA_LOG_FORMAT \ - "%" PRIu32 " \x1b[35moptiga\x1b[0m \x1b[32mDEBUG\x1b[0m %s: " -#else -#define OPTIGA_LOG_FORMAT "%" PRIu32 " optiga DEBUG %s: " -#endif -static void optiga_log_hex(const char *prefix, const uint8_t *data, - size_t data_size) { - printf(OPTIGA_LOG_FORMAT, hal_ticks_ms() * 1000, prefix); - for (size_t i = 0; i < data_size; i++) { - printf("%02x", data[i]); +int main(uint32_t cmd, void *arg) { + if (cmd == 1) { + systask_postmortem_t *info = (systask_postmortem_t *)arg; + rsod_gui(info); + system_exit(0); } - printf("\n"); -} -#endif -#endif - -int main(void) { - random_delays_init(); - -#ifdef RDI - rdi_start(); -#endif - - // reinitialize HAL for Trezor One -#if defined TREZOR_MODEL_1 - HAL_Init(); -#endif - -#ifdef SYSTEM_VIEW - enable_systemview(); -#endif - -#ifdef USE_HASH_PROCESSOR - hash_processor_init(); -#endif - -#ifdef USE_DMA2D - dma2d_init(); -#endif - - display_reinit(); - -#ifdef STM32U5 - check_oem_keys(); -#endif screen_boot_stage_2(); -#if !defined TREZOR_MODEL_1 - parse_boardloader_capabilities(); - - unit_variant_init(); - -#ifdef STM32U5 - secure_aes_init(); -#endif - -#ifdef USE_OPTIGA - uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0}; - secbool secret_ok = secret_optiga_get(secret); -#endif - - mpu_config_firmware_initial(); - - collect_hw_entropy(); - -#if PRODUCTION || BOOTLOADER_QA - check_and_replace_bootloader(); -#endif - // Enable MPU - mpu_config_firmware(); -#endif - - // Init peripherals - pendsv_init(); - - fault_handlers_init(); - -#if defined TREZOR_MODEL_T - set_core_clock(CLOCK_180_MHZ); -#endif - -#ifdef USE_BUTTON - button_init(); -#endif - -#ifdef USE_RGB_LED - rgb_led_init(); -#endif - -#ifdef USE_CONSUMPTION_MASK - consumption_mask_init(); -#endif - -#ifdef USE_I2C - i2c_init(); -#endif - -#ifdef USE_TOUCH - touch_init(); -#endif - -#ifdef USE_SD_CARD - sdcard_init(); -#endif - -#ifdef USE_HAPTIC - haptic_init(); -#endif - -#ifdef USE_OPTIGA - -#if !PYOPT - // command log is relatively quiet so we enable it in debug builds - optiga_command_set_log_hex(optiga_log_hex); - // transport log can be spammy, uncomment if you want it: - // optiga_transport_set_log_hex(optiga_log_hex); -#endif - - optiga_init(); - if (sectrue == secret_ok) { - // If the shielded connection cannot be established, reset Optiga and - // continue without it. In this case, OID_KEY_FIDO and OID_KEY_DEV cannot be - // used, which means device and FIDO attestation will not work. - if (optiga_sec_chan_handshake(secret, sizeof(secret)) != OPTIGA_SUCCESS) { - optiga_soft_reset(); - } - } - memzero(secret, sizeof(secret)); - ensure(sectrue * (optiga_open_application() == OPTIGA_SUCCESS), - "Cannot initialize optiga."); -#endif - -#if !defined TREZOR_MODEL_1 - drop_privileges(); -#endif - #ifdef USE_SECP256K1_ZKP ensure(sectrue * (zkp_context_init() == 0), NULL); #endif diff --git a/core/embed/firmware/memory_1.ld b/core/embed/firmware/memory_1.ld deleted file mode 100644 index 625c2c64198..00000000000 --- a/core/embed/firmware/memory_1.ld +++ /dev/null @@ -1,74 +0,0 @@ -/* TREZORv1 firmware linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 1024K - 64K - SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 128K -} - -main_stack_base = ORIGIN(SRAM) + SIZEOF(.stack); /* 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 */ -data_lma = LOADADDR(.data); -data_vma = ADDR(.data); -data_size = SIZEOF(.data); - -/* used by the startup code to wipe memory */ -/* we have no CCMRAM, so erase the first word of SRAM as hack */ -ccmram_start = ORIGIN(SRAM); -ccmram_end = ORIGIN(SRAM) + 4; - -/* used by the startup code to wipe memory */ -sram_start = ORIGIN(SRAM); -sram_end = ORIGIN(SRAM) + LENGTH(SRAM); -_ram_start = sram_start; -_ram_end = sram_end; - -_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.exidx); -_flash_start = ORIGIN(FLASH); -_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); -_heap_start = ADDR(.heap); -_heap_end = ADDR(.heap) + SIZEOF(.heap); - -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 - - /* exception handling info generated by llvm which should consist of 8 bytes of "cantunwind" */ - .exidx : ALIGN(4) { - *(.ARM.exidx*); - . = ALIGN(4); - } >FLASH AT>FLASH - - .stack : ALIGN(8) { - . = 16K; /* Exactly 16K allocated for stack. Overflow causes MemManage fault (when using MPU). */ - } >SRAM - - .data : ALIGN(4) { - *(.data*); - . = ALIGN(512); - } >SRAM AT>FLASH - - .bss : ALIGN(4) { - *(.bss*); - . = ALIGN(4); - } >SRAM - - .heap : ALIGN(4) { - . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ - . = ABSOLUTE(sram_end - 8); /* this explicitly sets the end of the heap, T1 bootloader had 8 bytes reserved at end */ - } >SRAM -} diff --git a/core/embed/firmware/memory_1_min.ld b/core/embed/firmware/memory_1_min.ld deleted file mode 100644 index 625c2c64198..00000000000 --- a/core/embed/firmware/memory_1_min.ld +++ /dev/null @@ -1,74 +0,0 @@ -/* TREZORv1 firmware linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 1024K - 64K - SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 128K -} - -main_stack_base = ORIGIN(SRAM) + SIZEOF(.stack); /* 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 */ -data_lma = LOADADDR(.data); -data_vma = ADDR(.data); -data_size = SIZEOF(.data); - -/* used by the startup code to wipe memory */ -/* we have no CCMRAM, so erase the first word of SRAM as hack */ -ccmram_start = ORIGIN(SRAM); -ccmram_end = ORIGIN(SRAM) + 4; - -/* used by the startup code to wipe memory */ -sram_start = ORIGIN(SRAM); -sram_end = ORIGIN(SRAM) + LENGTH(SRAM); -_ram_start = sram_start; -_ram_end = sram_end; - -_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.exidx); -_flash_start = ORIGIN(FLASH); -_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); -_heap_start = ADDR(.heap); -_heap_end = ADDR(.heap) + SIZEOF(.heap); - -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 - - /* exception handling info generated by llvm which should consist of 8 bytes of "cantunwind" */ - .exidx : ALIGN(4) { - *(.ARM.exidx*); - . = ALIGN(4); - } >FLASH AT>FLASH - - .stack : ALIGN(8) { - . = 16K; /* Exactly 16K allocated for stack. Overflow causes MemManage fault (when using MPU). */ - } >SRAM - - .data : ALIGN(4) { - *(.data*); - . = ALIGN(512); - } >SRAM AT>FLASH - - .bss : ALIGN(4) { - *(.bss*); - . = ALIGN(4); - } >SRAM - - .heap : ALIGN(4) { - . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ - . = ABSOLUTE(sram_end - 8); /* this explicitly sets the end of the heap, T1 bootloader had 8 bytes reserved at end */ - } >SRAM -} diff --git a/core/embed/firmware/memory_DISC1.ld b/core/embed/firmware/memory_DISC1.ld deleted file mode 120000 index 3f68ec99f6c..00000000000 --- a/core/embed/firmware/memory_DISC1.ld +++ /dev/null @@ -1 +0,0 @@ -memory_T.ld \ No newline at end of file diff --git a/core/embed/firmware/memory_DISC2.ld b/core/embed/firmware/memory_DISC2.ld deleted file mode 100644 index ae6d1272926..00000000000 --- a/core/embed/firmware/memory_DISC2.ld +++ /dev/null @@ -1,130 +0,0 @@ -/* TREZORv2 firmware linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 - 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); -_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 */ -confidential_lma = LOADADDR(.confidential); -confidential_vma = ADDR(.confidential); -confidential_size = SIZEOF(.confidential); - -/* 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); - -_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); -_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(1024) { - 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); - *(.buf*); - . = 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; /* Overflow causes UsageFault */ - } >SRAM2 - - .confidential : ALIGN(512) { - *(.confidential*); - . = 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 - - .boot_args : ALIGN(8) { - *(.boot_command*); - . = ALIGN(8); - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS -} diff --git a/core/embed/firmware/memory_R.ld b/core/embed/firmware/memory_R.ld deleted file mode 120000 index 3f68ec99f6c..00000000000 --- a/core/embed/firmware/memory_R.ld +++ /dev/null @@ -1 +0,0 @@ -memory_T.ld \ No newline at end of file diff --git a/core/embed/firmware/memory_T3B1.ld b/core/embed/firmware/memory_T3B1.ld deleted file mode 120000 index b5bfd3715e0..00000000000 --- a/core/embed/firmware/memory_T3B1.ld +++ /dev/null @@ -1 +0,0 @@ -memory_T3T1.ld \ No newline at end of file diff --git a/core/embed/firmware/mpconfigport.h b/core/embed/firmware/mpconfigport.h index b80f257c606..0e9e990b1b6 100644 --- a/core/embed/firmware/mpconfigport.h +++ b/core/embed/firmware/mpconfigport.h @@ -194,8 +194,8 @@ typedef long mp_off_t; #include "irq.h" -#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq() -#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) +#define MICROPY_BEGIN_ATOMIC_SECTION() irq_lock() +#define MICROPY_END_ATOMIC_SECTION(state) irq_unlock(state) #define MICROPY_EVENT_POLL_HOOK \ do { \ extern void mp_handle_pending(bool); \ diff --git a/core/embed/firmware/mphalport.c b/core/embed/firmware/mphalport.c index 4c9d2a97f57..9509ca37d55 100644 --- a/core/embed/firmware/mphalport.c +++ b/core/embed/firmware/mphalport.c @@ -19,6 +19,8 @@ #include "common.h" #include "py/mphal.h" + +#include "systick.h" #include "usb.h" static int vcp_iface_num = -1; @@ -45,3 +47,11 @@ void mp_hal_set_vcp_iface(int iface_num) { vcp_iface_num = iface_num; } // Dummy implementation required by ports/stm32/gccollect.c. // The normal version requires MICROPY_ENABLE_SCHEDULER which we don't use. void soft_timer_gc_mark_all(void) {} + +void mp_hal_delay_ms(mp_uint_t Delay) { systick_delay_ms(Delay); } + +void mp_hal_delay_us(mp_uint_t usec) { systick_delay_us(usec); } + +mp_uint_t mp_hal_ticks_ms(void) { return systick_ms(); } + +mp_uint_t mp_hal_ticks_us(void) { return systick_ms() * 1000; } diff --git a/core/embed/firmware/startup_stm32f4.S b/core/embed/firmware/startup_stm32f4.S deleted file mode 100644 index 7d0fadf2cda..00000000000 --- a/core/embed/firmware/startup_stm32f4.S +++ /dev/null @@ -1,69 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - -// The following loading of VTOR address only works if T1 bootloader was built with PRODUCTION=0 -// or the firmware was properly signed. All other variants end up in hard fault due to MPU -// (cf mpu_config_firmware in legacy bootloader) - -#if defined TREZOR_MODEL_1 - cpsid if - ldr r0, =0xE000ED08 // r0 = VTOR address - ldr r1, =0x08010400 // r1 = FLASH_APP_START - str r1, [r0] // assign - - ldr r0, =_estack // r0 = stack pointer - msr msp, r0 // set stack pointer - dsb - isb -#endif - - // setup environment for subsequent stage of code - ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM - ldr r2, =0 // r2 - the word-sized value to be written - bl memset_reg - - ldr r0, =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 - ldr r2, =0 // r2 - the word-sized value to be written - bl memset_reg - - ldr r0, =sram_start // r0 - point to beginning of SRAM - ldr r1, =sram_end // r1 - point to byte after the end of SRAM - ldr r2, =0 // r2 - the word-sized value to be written - bl memset_reg - - // 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 - - // 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." -#if defined STM32F405xx - cpsie if -#elif defined STM32F427xx || defined STM32F429xx - cpsie f -#else - #error "Unknown MCU" -#endif - - // enter the application code - bl main - - b shutdown_privileged - - .end diff --git a/core/embed/firmware/startup_stm32u5.S b/core/embed/firmware/startup_stm32u5.S deleted file mode 100644 index f37f5b09285..00000000000 --- a/core/embed/firmware/startup_stm32u5.S +++ /dev/null @@ -1,72 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // set the stack protection - ldr r0, =_sstack - add r0, r0, #16 // padding - msr MSPLIM, r0 - - // 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 confidential data in from flash - ldr r0, =confidential_vma // dst addr - ldr r1, =confidential_lma // src addr - ldr r2, =confidential_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/firmware/systemview.c b/core/embed/firmware/systemview.c index 06fc221e32d..91021d2f013 100644 --- a/core/embed/firmware/systemview.c +++ b/core/embed/firmware/systemview.c @@ -6,7 +6,6 @@ #include #include "irq.h" #include "mpconfigport.h" -#include "supervise.h" #include "SEGGER_SYSVIEW.h" #include "SEGGER_SYSVIEW_Conf.h" @@ -52,6 +51,12 @@ typedef struct { extern uint32_t SystemCoreClock; +static inline uint32_t is_mode_unprivileged(void) { + uint32_t r0; + __asm__ volatile("mrs %0, control" : "=r"(r0)); + return r0 & 1; +} + uint32_t svc_get_dwt_cyccnt() { if (is_mode_unprivileged()) { __asm__ __volatile__("svc %0" ::"i"(SVC_GET_DWT_CYCCNT)); diff --git a/core/embed/kernel/main.c b/core/embed/kernel/main.c new file mode 100644 index 00000000000..376f3d2dca0 --- /dev/null +++ b/core/embed/kernel/main.c @@ -0,0 +1,267 @@ +/* + * 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 "applet.h" +#include "bl_check.h" +#include "board_capabilities.h" +#include "bootutils.h" +#include "button.h" +#include "consumption_mask.h" +#include "display.h" +#include "dma2d.h" +#include "entropy.h" +#include "haptic.h" +#include "image.h" +#include "irq.h" +#include "memzero.h" +#include "mpu.h" +#include "optiga_commands.h" +#include "optiga_transport.h" +#include "random_delays.h" +#include "rsod.h" +#include "sdcard.h" +#include "secret.h" +#include "secure_aes.h" +#include "system.h" +#include "systick.h" +#include "tamper.h" +#include "touch.h" +#include "unit_variant.h" + +#ifdef USE_OPTIGA +#if !PYOPT +#include +#if 1 // color log +#define OPTIGA_LOG_FORMAT \ + "%" PRIu32 " \x1b[35moptiga\x1b[0m \x1b[32mDEBUG\x1b[0m %s: " +#else +#define OPTIGA_LOG_FORMAT "%" PRIu32 " optiga DEBUG %s: " +#endif +static void optiga_log_hex(const char *prefix, const uint8_t *data, + size_t data_size) { + printf(OPTIGA_LOG_FORMAT, hal_ticks_ms() * 1000, prefix); + for (size_t i = 0; i < data_size; i++) { + printf("%02x", data[i]); + } + printf("\n"); +} +#endif +#endif + +void drivers_init() { +#if defined TREZOR_MODEL_T + set_core_clock(CLOCK_180_MHZ); +#endif + +#ifdef STM32U5 + tamper_init(); +#endif + + rdi_init(); + +#ifdef RDI + rdi_start(); +#endif + +#ifdef SYSTEM_VIEW + enable_systemview(); +#endif + +#ifdef USE_HASH_PROCESSOR + hash_processor_init(); +#endif + +#ifdef USE_DMA2D + dma2d_init(); +#endif + + display_init(DISPLAY_JUMP_BEHAVIOR); + +#ifdef STM32U5 + check_oem_keys(); +#endif + + parse_boardloader_capabilities(); + + unit_variant_init(); + +#ifdef STM32U5 + secure_aes_init(); +#endif + +#ifdef USE_OPTIGA + uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0}; + secbool secret_ok = secret_optiga_get(secret); +#endif + + entropy_init(); + +#if PRODUCTION || BOOTLOADER_QA + check_and_replace_bootloader(); +#endif + +#ifdef USE_BUTTON + button_init(); +#endif + +#ifdef USE_RGB_LED + rgb_led_init(); +#endif + +#ifdef USE_CONSUMPTION_MASK + consumption_mask_init(); +#endif + +#ifdef USE_TOUCH + touch_init(); +#endif + +#ifdef USE_SD_CARD + sdcard_init(); +#endif + +#ifdef USE_HAPTIC + haptic_init(); +#endif + +#ifdef USE_OPTIGA + +#if !PYOPT + // command log is relatively quiet so we enable it in debug builds + optiga_command_set_log_hex(optiga_log_hex); + // transport log can be spammy, uncomment if you want it: + // optiga_transport_set_log_hex(optiga_log_hex); +#endif + + optiga_init(); + if (sectrue == secret_ok) { + // If the shielded connection cannot be established, reset Optiga and + // continue without it. In this case, OID_KEY_FIDO and OID_KEY_DEV cannot be + // used, which means device and FIDO attestation will not work. + if (optiga_sec_chan_handshake(secret, sizeof(secret)) != OPTIGA_SUCCESS) { + optiga_soft_reset(); + } + } + memzero(secret, sizeof(secret)); + ensure(sectrue * (optiga_open_application() == OPTIGA_SUCCESS), + "Cannot initialize optiga."); + +#endif +} + +// defined in linker script +extern uint32_t _codelen; +extern uint32_t _coreapp_clear_ram_0_start; +extern uint32_t _coreapp_clear_ram_0_size; +extern uint32_t _coreapp_clear_ram_1_start; +extern uint32_t _coreapp_clear_ram_1_size; +#define KERNEL_SIZE (uint32_t) & _codelen + +// Initializes coreapp applet +static void coreapp_init(applet_t *applet) { + applet_header_t *coreapp_header = + (applet_header_t *)COREAPP_CODE_ALIGN(KERNEL_START + KERNEL_SIZE); + + applet_layout_t coreapp_layout = { + .data1_start = (uint32_t)&_coreapp_clear_ram_0_start, + .data1_size = (uint32_t)&_coreapp_clear_ram_0_size, + .data2_start = (uint32_t)&_coreapp_clear_ram_1_start, + .data2_size = (uint32_t)&_coreapp_clear_ram_1_size, + }; + + applet_init(applet, coreapp_header, &coreapp_layout); +} + +// Shows RSOD (Red Screen of Death) +static void show_rsod(const systask_postmortem_t *pminfo) { +#ifdef FANCY_FATAL_ERROR + applet_t coreapp; + coreapp_init(&coreapp); + + // Reset and run the coreapp in RSOD mode + if (applet_reset(&coreapp, 1, pminfo, sizeof(systask_postmortem_t))) { + systask_yield_to(&coreapp.task); + + if (coreapp.task.pminfo.reason == TASK_TERM_REASON_EXIT) { + // If the RSOD was shown successfully, proceed to shutdown + secure_shutdown(); + } + } +#endif + + // If coreapp crashed, fallback to showing the error using a terminal + rsod_terminal(pminfo); +} + +// Initializes system in emergency mode and shows RSOD +static void init_and_show_rsod(const systask_postmortem_t *pminfo) { + // Initialize the system's core services + // (If the kernel crashes in emergency mode, we are out of options + // and show the RSOD without attempting to re-enter emergency mode) + system_init(&rsod_terminal); + + // Initialize necessary drivers + display_init(DISPLAY_RESET_CONTENT); + + // Show RSOD + show_rsod(pminfo); + + // Wait for the user to manually power off the device + secure_shutdown(); +} + +// Kernel panic handler +// (may be called from interrupt context) +static void kernel_panic(const systask_postmortem_t *pminfo) { + // Since the system state is unreliable, enter emergency mode + // and show the RSOD. + system_emergency_rescue(&init_and_show_rsod, pminfo); + // The previous function call never returns +} + +int main(void) { + // Initialize system's core services + system_init(&kernel_panic); + + // Initialize hardware drivers + drivers_init(); + + // Initialize coreapp task + applet_t coreapp; + coreapp_init(&coreapp); + + // Reset and run the coreapp + if (!applet_reset(&coreapp, 0, NULL, 0)) { + error_shutdown("Cannot start coreapp"); + } + + systask_yield_to(&coreapp.task); + + // Coreapp crashed, show RSOD + show_rsod(&coreapp.task.pminfo); + + // Wait for the user to manually power off the device + secure_shutdown(); + + return 0; +} diff --git a/core/embed/kernel/version.h b/core/embed/kernel/version.h new file mode 100644 index 00000000000..4a3ed90d599 --- /dev/null +++ b/core/embed/kernel/version.h @@ -0,0 +1,11 @@ +#define VERSION_MAJOR 2 +#define VERSION_MINOR 8 +#define VERSION_PATCH 1 +#define VERSION_BUILD 0 + +#define FIX_VERSION_MAJOR 2 +#define FIX_VERSION_MINOR 8 +#define FIX_VERSION_PATCH 0 +#define FIX_VERSION_BUILD 0 + +#define VERSION_MONOTONIC 1 diff --git a/core/embed/firmware/bl_check.c b/core/embed/lib/bl_check.c similarity index 93% rename from core/embed/firmware/bl_check.c rename to core/embed/lib/bl_check.c index c172df62d6a..0274f2aa2f1 100644 --- a/core/embed/firmware/bl_check.c +++ b/core/embed/lib/bl_check.c @@ -26,13 +26,12 @@ #include "image.h" #include "memzero.h" #include "model.h" +#include "mpu.h" #include "uzlib.h" // symbols from bootloader.bin => bootloader.o -extern const void - _binary_embed_firmware_bootloaders_bootloader_bin_deflated_start; -extern const void - _binary_embed_firmware_bootloaders_bootloader_bin_deflated_size; +extern const void _binary_embed_bootloaders_bootloader_bin_deflated_start; +extern const void _binary_embed_bootloaders_bootloader_bin_deflated_size; #define CONCAT_NAME_HELPER(prefix, name, suffix) prefix##name##suffix #define CONCAT_NAME(name, var) CONCAT_NAME_HELPER(BOOTLOADER_, name, var) @@ -82,6 +81,7 @@ static void uzlib_prepare(struct uzlib_uncomp *decomp, uint8_t *window, void check_and_replace_bootloader(void) { #if PRODUCTION || BOOTLOADER_QA + mpu_mode_t mode = mpu_reconfig(MPU_MODE_BOOTUPDATE); // compute current bootloader hash uint8_t hash[BLAKE2S_DIGEST_LENGTH]; @@ -95,15 +95,16 @@ void check_and_replace_bootloader(void) { // do we have the latest bootloader? if (sectrue == latest_bootloader(hash, BLAKE2S_DIGEST_LENGTH)) { + mpu_reconfig(mode); return; } // replace bootloader with the latest one const uint32_t *data = (const uint32_t - *)&_binary_embed_firmware_bootloaders_bootloader_bin_deflated_start; + *)&_binary_embed_bootloaders_bootloader_bin_deflated_start; const uint32_t len = - (const uint32_t)&_binary_embed_firmware_bootloaders_bootloader_bin_deflated_size; + (const uint32_t)&_binary_embed_bootloaders_bootloader_bin_deflated_size; struct uzlib_uncomp decomp = {0}; uint8_t decomp_window[UZLIB_WINDOW_SIZE] = {0}; @@ -134,6 +135,7 @@ void check_and_replace_bootloader(void) { if (new_bld_hdr->monotonic < current_bld_hdr->monotonic) { // reject downgrade + mpu_reconfig(mode); return; } @@ -180,5 +182,7 @@ void check_and_replace_bootloader(void) { } ensure(flash_lock_write(), NULL); + + mpu_reconfig(mode); #endif } diff --git a/core/embed/firmware/bl_check.h b/core/embed/lib/bl_check.h similarity index 100% rename from core/embed/firmware/bl_check.h rename to core/embed/lib/bl_check.h diff --git a/core/embed/lib/error_handling.c b/core/embed/lib/error_handling.c index f93636c058a..cfaab483796 100644 --- a/core/embed/lib/error_handling.c +++ b/core/embed/lib/error_handling.c @@ -18,48 +18,24 @@ */ #include -#ifdef TREZOR_EMULATOR -#include -#endif +#include -#include "common.h" -#include "display.h" #include "error_handling.h" -#include "mini_printf.h" -#ifdef FANCY_FATAL_ERROR -#include "rust_ui.h" -#else -#include "terminal.h" -#endif +#include "system.h" -#ifdef RGB16 -#define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00) -#else -#define COLOR_FATAL_ERROR COLOR_BLACK -#endif +uint32_t __stack_chk_guard = 0; + +// Calls to this function are inserted by the compiler +// when stack protection is enabled. +void __attribute__((noreturn, used)) __stack_chk_fail(void) { + error_shutdown("(SS)"); +} void __attribute__((noreturn)) error_shutdown_ex(const char *title, const char *message, const char *footer) { - if (title == NULL) { - title = "INTERNAL ERROR"; - } - if (footer == NULL) { - footer = "PLEASE VISIT\nTREZOR.IO/RSOD"; - } - -#ifdef FANCY_FATAL_ERROR - error_shutdown_rust(title, message, footer); -#else - display_orientation(0); - term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); - term_printf("%s\n", title); - if (message) { - term_printf("%s\n", message); - } - term_printf("\n%s\n", footer); - display_backlight(255); - trezor_shutdown(); -#endif + system_exit_error(title, message, footer); + while (1) + ; } void __attribute__((noreturn)) error_shutdown(const char *message) { @@ -68,39 +44,9 @@ void __attribute__((noreturn)) error_shutdown(const char *message) { void __attribute__((noreturn)) __fatal_error(const char *msg, const char *file, int line) { -#ifdef TREZOR_EMULATOR - fprintf(stderr, "FATAL ERROR: %s\n", msg); - if (file) { - fprintf(stderr, "file: %s:%d\n", file, line); - } - fflush(stderr); -#endif -#ifdef FANCY_FATAL_ERROR - if (msg == NULL) { - char buf[128] = {0}; - mini_snprintf(buf, sizeof(buf), "%s:%d", file, line); - msg = buf; - } - error_shutdown(msg); -#else - display_orientation(0); - term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); - term_printf("\nINTERNAL ERROR:\n"); - if (msg) { - term_printf("msg : %s\n", msg); - } - if (file) { - term_printf("file: %s:%d\n", file, line); - } -#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"); - display_backlight(255); - trezor_shutdown(); -#endif + system_exit_fatal(msg, file, line); + while (1) + ; } void __attribute__((noreturn)) show_wipe_code_screen(void) { diff --git a/core/embed/lib/flash_utils.c b/core/embed/lib/flash_utils.c new file mode 100644 index 00000000000..5c4c6183b7a --- /dev/null +++ b/core/embed/lib/flash_utils.c @@ -0,0 +1,105 @@ +/* + * 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 TREZOR_BOARD + +#include "flash_utils.h" +#include "common.h" +#include "flash_area.h" +#include "model.h" +#include "mpu.h" +#include "secbool.h" + +typedef struct { + const flash_area_t* area; + mpu_mode_t mpu_mode; +} flash_area_ref_t; + +// Erases the given list of flash areas. +// +// Invokes the progress_cb after each erased sector or page. +static secbool erase_areas(const flash_area_ref_t* areas, int area_count, + flash_progress_callback_t progress_cb) { + int total = 0; + int progress = 0; + + for (int i = 0; i < area_count; i++) { + total += flash_area_get_size(areas[i].area); + } + + mpu_mode_t mpu_mode = mpu_get_mode(); + + for (int i = 0; i < area_count; i++) { + const flash_area_t* area = areas[i].area; + uint32_t offset = 0; + uint32_t bytes_erased = 0; + + mpu_reconfig(areas[i].mpu_mode); + + do { + if (progress_cb) { + progress_cb(progress, total); + } + + if (sectrue != flash_area_erase_partial(area, offset, &bytes_erased)) { + mpu_restore(mpu_mode); + return secfalse; + } + + offset += bytes_erased; + progress += bytes_erased; + + } while (bytes_erased > 0); + } + + mpu_restore(mpu_mode); + return sectrue; +} + +secbool erase_storage(flash_progress_callback_t progress_cb) { + _Static_assert(STORAGE_AREAS_COUNT == 2, + "Unsupported number of storage areas"); + + static const flash_area_ref_t areas[] = { + {.area = &STORAGE_AREAS[0], .mpu_mode = MPU_MODE_STORAGE}, + {.area = &STORAGE_AREAS[1], .mpu_mode = MPU_MODE_STORAGE}, + }; + + return erase_areas(areas, ARRAY_LENGTH(areas), progress_cb); +} + +secbool erase_device(flash_progress_callback_t progress_cb) { + _Static_assert(STORAGE_AREAS_COUNT == 2, + "Unsupported number of storage areas"); + + static const flash_area_ref_t areas[] = { + {.area = &STORAGE_AREAS[0], .mpu_mode = MPU_MODE_STORAGE}, + {.area = &STORAGE_AREAS[1], .mpu_mode = MPU_MODE_STORAGE}, + {.area = &TRANSLATIONS_AREA, .mpu_mode = MPU_MODE_ASSETS}, +#if defined(BOARDLOADER) || defined(BOOTLOADER) + {.area = &FIRMWARE_AREA, .mpu_mode = MPU_MODE_DEFAULT}, +#endif +#if defined(BOARDLOADER) && defined(USE_SD_CARD) + {.area = &BOOTLOADER_AREA, .mpu_mode = MPU_MODE_DEFAULT}, + {.area = &UNUSED_AREA, .mpu_mode = MPU_MODE_UNUSED_FLASH}, +#endif + }; + + return erase_areas(areas, ARRAY_LENGTH(areas), progress_cb); +} diff --git a/core/embed/lib/flash_utils.h b/core/embed/lib/flash_utils.h new file mode 100644 index 00000000000..04f14d87922 --- /dev/null +++ b/core/embed/lib/flash_utils.h @@ -0,0 +1,46 @@ +/* + * 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 LIB_FLASH_UTILS_H +#define LIB_FLASH_UTILS_H + +#include "secbool.h" + +#ifdef KERNEL_MODE + +// Progress callback function called during the flash erase operation. +// +// Progress is reported as: (100 * pos) / total [%]. +typedef void (*flash_progress_callback_t)(int pos, int total); + +// Erases both storage areas +// +// Callback is invoked after each sector or page is erased. +secbool erase_storage(flash_progress_callback_t progress_cb); + +// Erases all flash areas including storage, assets and firmware. +// +// If called from boardloader, also erases bootloader area. +// +// Callback is invoked after each sector or page is erased. +secbool erase_device(flash_progress_callback_t progress_cb); + +#endif // KERNEL_MODE + +#endif // LIB_FLASH_UTILS_H diff --git a/core/embed/lib/image.h b/core/embed/lib/image.h index bfcfba634b0..f837f7d9690 100644 --- a/core/embed/lib/image.h +++ b/core/embed/lib/image.h @@ -39,6 +39,12 @@ #define IMAGE_CODE_ALIGN(addr) \ ((((uint32_t)(uintptr_t)addr) + (CODE_ALIGNMENT - 1)) & ~(CODE_ALIGNMENT - 1)) +#define COREAPP_ALIGNMENT 512 + +#define COREAPP_CODE_ALIGN(addr) \ + ((((uint32_t)(uintptr_t)addr) + (COREAPP_ALIGNMENT - 1)) & \ + ~(COREAPP_ALIGNMENT - 1)) + typedef struct { uint32_t magic; uint32_t hdrlen; diff --git a/core/embed/lib/rsod.c b/core/embed/lib/rsod.c new file mode 100644 index 00000000000..7be3da488b9 --- /dev/null +++ b/core/embed/lib/rsod.c @@ -0,0 +1,177 @@ +/* + * 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 "rsod.h" +#include "bootutils.h" +#include "display.h" +#include "mini_printf.h" +#include "system.h" +#include "terminal.h" + +#define RSOD_DEFAULT_TITLE "INTERNAL ERROR"; +#define RSOD_DEFAULT_MESSAGE "UNSPECIFIED"; +#define RSOD_DEFAULT_FOOTER "PLEASE VISIT TREZOR.IO/RSOD"; +#define RSOD_EXIT_MESSAGE "EXIT %d" + +#ifdef KERNEL_MODE + +#define RSOD_FG_COLOR COLOR_WHITE + +#ifdef USE_RGB_COLORS +#define RSOD_BG_COLOR RGB16(0x7F, 0x00, 0x00) +#else +#define RSOD_BG_COLOR COLOR_BLACK +#endif + +void rsod_terminal(const systask_postmortem_t* pminfo) { + display_orientation(0); + term_set_color(RSOD_FG_COLOR, RSOD_BG_COLOR); + + const char* title = RSOD_DEFAULT_TITLE; + const char* message = RSOD_DEFAULT_MESSAGE; + const char* footer = RSOD_DEFAULT_FOOTER; + const char* file = NULL; + char message_buf[32] = {0}; + int line = 0; + + switch (pminfo->reason) { + case TASK_TERM_REASON_EXIT: + mini_snprintf(message_buf, sizeof(message_buf), RSOD_EXIT_MESSAGE, + pminfo->exit.code); + message = message_buf; + break; + case TASK_TERM_REASON_ERROR: + title = pminfo->error.title; + message = pminfo->error.message; + footer = pminfo->error.footer; + break; + case TASK_TERM_REASON_FATAL: + message = pminfo->fatal.expr; + file = pminfo->fatal.file; + line = pminfo->fatal.line; + break; + case TASK_TERM_REASON_FAULT: + message = system_fault_message(&pminfo->fault); + break; + } + + if (title != NULL) { + term_printf("%s\n", title); + } + + if (message != NULL) { + term_printf("msg : %s\n", message); + } + + if (file) { + term_printf("file: %s:%d\n", file, line); + } + +#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 + + if (footer != NULL) { + term_printf("\n%s\n", footer); + } + + display_backlight(255); +} + +#endif // KERNEL_MODE + +#if (defined(FIRMWARE) || defined(BOOTLOADER)) && defined(FANCY_FATAL_ERROR) + +#include "rust_ui.h" + +void rsod_gui(const systask_postmortem_t* pminfo) { + const char* title = RSOD_DEFAULT_TITLE; + const char* message = RSOD_DEFAULT_MESSAGE; + const char* footer = RSOD_DEFAULT_FOOTER; + char message_buf[128] = {0}; + + switch (pminfo->reason) { + case TASK_TERM_REASON_EXIT: + mini_snprintf(message_buf, sizeof(message_buf), RSOD_EXIT_MESSAGE, + pminfo->exit.code); + message = message_buf; + break; + + case TASK_TERM_REASON_ERROR: + title = pminfo->error.title; + message = pminfo->error.message; + footer = pminfo->error.footer; + break; + + case TASK_TERM_REASON_FATAL: + message = pminfo->fatal.expr; + if (message[0] == '\0') { + mini_snprintf(message_buf, sizeof(message_buf), "%s:%u", + pminfo->fatal.file, (unsigned int)pminfo->fatal.line); + message = message_buf; + } + break; + + case TASK_TERM_REASON_FAULT: + message = system_fault_message(&pminfo->fault); + break; + } + + // Render the RSOD in Rust + display_rsod_rust(title, message, footer); +} + +#endif + +#ifdef KERNEL_MODE + +// Initializes system in emergency mode and shows RSOD +static void init_and_show_rsod(const systask_postmortem_t* pminfo) { + // Initialize the system's core services + // (If the kernel crashes in emergency mode, we are out of options + // and show the RSOD without attempting to re-enter emergency mode) + system_init(&rsod_terminal); + + // Initialize necessary drivers + display_init(DISPLAY_RESET_CONTENT); + +#if (defined(FIRMWARE) || defined(BOOTLOADER)) && defined(FANCY_FATAL_ERROR) + // Show the RSOD using Rust GUI + rsod_gui(pminfo); +#else + // Show the RSOD using terminal + rsod_terminal(pminfo); +#endif + + // Wait for the user to manually power off the device + secure_shutdown(); +} + +// Universal panic handler +// (may be called from interrupt context) +void rsod_panic_handler(const systask_postmortem_t* pminfo) { + // Since the system state is unreliable, enter emergency mode + // and show the RSOD. + system_emergency_rescue(&init_and_show_rsod, pminfo); + // The previous function call never returns +} + +#endif // KERNEL_MODE diff --git a/core/embed/lib/rsod.h b/core/embed/lib/rsod.h new file mode 100644 index 00000000000..86f302d8617 --- /dev/null +++ b/core/embed/lib/rsod.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 LIB_RSOD_H +#define LIB_RSOD_H + +#include "systask.h" + +// Shows RSOD (Red Screen of Death) using terminal. +void rsod_terminal(const systask_postmortem_t* pminfo); + +// Shows RSOD (Red Screen of Death) using Rust GUI. +void rsod_gui(const systask_postmortem_t* pminfo); + +#ifdef KERNEL_MODE + +// Universal panic handler that can be passed to `system_init()` function +// to show RSOD screen describing the system error. +// (may be called from interrupt context) +void rsod_panic_handler(const systask_postmortem_t* pminfo); + +#endif // KERNEL_MODE + +#endif // LIB_RSOD_H diff --git a/core/embed/lib/sizedefs.h b/core/embed/lib/sizedefs.h index 9f8bb7a6c57..07889e1abcb 100644 --- a/core/embed/lib/sizedefs.h +++ b/core/embed/lib/sizedefs.h @@ -2,7 +2,10 @@ #define SIZEDEFS_H_ #define SIZE_2K (2 * 1024) +#define SIZE_3K (3 * 1024) +#define SIZE_8K (8 * 1024) #define SIZE_16K (16 * 1024) +#define SIZE_24K (24 * 1024) #define SIZE_48K (48 * 1024) #define SIZE_64K (64 * 1024) #define SIZE_128K (128 * 1024) diff --git a/core/embed/lib/terminal.c b/core/embed/lib/terminal.c index 0891fcbedf3..74ce9d7cb1d 100644 --- a/core/embed/lib/terminal.c +++ b/core/embed/lib/terminal.c @@ -81,8 +81,8 @@ static void term_redraw_rows(int start_row, int row_count) { .src_x = 0, .src_y = 0, .src_stride = 8, - .src_fg = terminal_fgcolor, - .src_bg = terminal_bgcolor, + .src_fg = gfx_color16_to_color(terminal_fgcolor), + .src_bg = gfx_color16_to_color(terminal_bgcolor), }; for (int y = start_row; y < start_row + row_count; y++) { @@ -159,9 +159,9 @@ void term_print(const char *text, int textlen) { } const uint8_t *g = Font_Bitmap + (5 * (c - ' ')); if (k < 5 && (g[k] & (1 << j))) { - PIXELDATA(terminal_fgcolor); + PIXELDATA(gfx_color16_to_color(terminal_fgcolor)); } else { - PIXELDATA(terminal_bgcolor); + PIXELDATA(gfx_color16_to_color(terminal_bgcolor)); } } display_pixeldata_dirty(); diff --git a/core/embed/lib/translations.c b/core/embed/lib/translations.c index d00fa0d483e..9f68a29b3ad 100644 --- a/core/embed/lib/translations.c +++ b/core/embed/lib/translations.c @@ -5,6 +5,9 @@ #include "common.h" #include "flash.h" #include "model.h" +#include "mpu.h" + +#ifdef KERNEL_MODE bool translations_write(const uint8_t* data, uint32_t offset, uint32_t len) { uint32_t size = translations_area_bytesize(); @@ -12,12 +15,17 @@ bool translations_write(const uint8_t* data, uint32_t offset, uint32_t len) { return false; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_ASSETS); + ensure(flash_unlock_write(), "translations_write unlock"); // todo consider alignment ensure(flash_area_write_data_padded(&TRANSLATIONS_AREA, offset, data, len, 0xFF, FLASH_ALIGN(len)), "translations_write write"); ensure(flash_lock_write(), "translations_write lock"); + + mpu_restore(mpu_mode); + return true; } @@ -30,9 +38,13 @@ const uint8_t* translations_read(uint32_t* len, uint32_t offset) { } void translations_erase(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_ASSETS); ensure(flash_area_erase(&TRANSLATIONS_AREA, NULL), "translations erase"); + mpu_restore(mpu_mode); } uint32_t translations_area_bytesize(void) { return flash_area_get_size(&TRANSLATIONS_AREA); } + +#endif // KERNEL_MODE diff --git a/core/embed/lib/translations.h b/core/embed/lib/translations.h index 6fede56ce17..9e823650b57 100644 --- a/core/embed/lib/translations.h +++ b/core/embed/lib/translations.h @@ -1,3 +1,25 @@ +/* + * 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 LIB_TRANSLATIONS_H +#define LIB_TRANSLATIONS_H + #include #include @@ -8,3 +30,5 @@ const uint8_t* translations_read(uint32_t* len, uint32_t offset); void translations_erase(void); uint32_t translations_area_bytesize(void); + +#endif // LIB_TRANSLATIONS_H diff --git a/core/embed/lib/unit_variant.c b/core/embed/lib/unit_variant.c index e062284de52..6fffb7049da 100644 --- a/core/embed/lib/unit_variant.c +++ b/core/embed/lib/unit_variant.c @@ -2,9 +2,12 @@ #include "flash_otp.h" #include "model.h" +#include "mpu.h" #include "unit_variant.h" #include TREZOR_BOARD +#ifdef KERNEL_MODE + static uint8_t unit_variant_color = 0; static uint8_t unit_variant_packaging = 0; static bool unit_variant_btconly = false; @@ -93,3 +96,5 @@ bool unit_variant_is_sd_hotswap_enabled(void) { #endif #endif } + +#endif // KERNEL_MODE diff --git a/core/embed/lib/unit_variant.h b/core/embed/lib/unit_variant.h index 3d08974e75d..fea6d77b0ca 100644 --- a/core/embed/lib/unit_variant.h +++ b/core/embed/lib/unit_variant.h @@ -4,7 +4,12 @@ #include #include +#ifdef KERNEL_MODE + void unit_variant_init(void); + +#endif // KERNEL_MODE + bool unit_variant_present(void); uint8_t unit_variant_get_color(void); uint8_t unit_variant_get_packaging(void); diff --git a/core/embed/models/D001/boards/stm32f429i-disc1.h b/core/embed/models/D001/boards/stm32f429i-disc1.h index cd37a97124e..28198342d25 100644 --- a/core/embed/models/D001/boards/stm32f429i-disc1.h +++ b/core/embed/models/D001/boards/stm32f429i-disc1.h @@ -24,7 +24,13 @@ #define I2C_INSTANCE_0_SCL_PORT GPIOA #define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_8 #define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOA_CLK_ENABLE -#define I2C_INSTANCE_0_RESET_FLG RCC_APB1RSTR_I2C3RST +#define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR +#define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR_I2C3RST +#define I2C_INSTANCE_0_EV_IRQHandler I2C3_EV_IRQHandler +#define I2C_INSTANCE_0_ER_IRQHandler I2C3_ER_IRQHandler +#define I2C_INSTANCE_0_EV_IRQn I2C3_EV_IRQn +#define I2C_INSTANCE_0_ER_IRQn I2C3_ER_IRQn +#define I2C_INSTANCE_0_GUARD_TIME 0 #define TOUCH_I2C_INSTANCE 0 diff --git a/core/embed/models/D001/memory.ld b/core/embed/models/D001/memory.ld new file mode 100644 index 00000000000..abce5a3951c --- /dev/null +++ b/core/embed/models/D001/memory.ld @@ -0,0 +1,36 @@ +/* Auto-generated file, do not edit.*/ + +FLASH_START = 0x8000000; +BOARDLOADER_START = 0x8000000; +BOOTLOADER_START = 0x8020000; +FIRMWARE_START = 0x8040000; +FIRMWARE_P2_START = 0x8120000; +KERNEL_START = 0x8040000; +STORAGE_1_OFFSET = 0x10000; +STORAGE_2_OFFSET = 0x110000; +NORCOW_SECTOR_SIZE = 0x10000; +BOARDLOADER_IMAGE_MAXSIZE = 0xc000; +BOOTLOADER_IMAGE_MAXSIZE = 0x20000; +FIRMWARE_IMAGE_MAXSIZE = 0x1a0000; +FIRMWARE_P1_IMAGE_MAXSIZE = 0xc0000; +FIRMWARE_P2_IMAGE_MAXSIZE = 0xe0000; +KERNEL_IMAGE_MAXSIZE = 0x80000; +BOARDLOADER_SECTOR_START = 0x0; +BOARDLOADER_SECTOR_END = 0x3; +BOOTLOADER_SECTOR_START = 0x5; +BOOTLOADER_SECTOR_END = 0x5; +FIRMWARE_SECTOR_START = 0x6; +FIRMWARE_SECTOR_END = 0xb; +FIRMWARE_P2_SECTOR_START = 0x11; +FIRMWARE_P2_SECTOR_END = 0x17; +STORAGE_1_SECTOR_START = 0x4; +STORAGE_1_SECTOR_END = 0x4; +STORAGE_2_SECTOR_START = 0x10; +STORAGE_2_SECTOR_END = 0x10; +KERNEL_STACK_SIZE = 0x2000; +KERNEL_CCMRAM_SIZE = 0x4000; +KERNEL_FRAMEBUFFER_SIZE = 0x0; +KERNEL_SRAM_SIZE = 0x400; +BOOTARGS_SIZE = 0x100; +BOARD_CAPABILITIES_ADDR = 0x800bf00; +CODE_ALIGNMENT = 0x200; diff --git a/core/embed/models/D001/model_D001.h b/core/embed/models/D001/model_D001.h index c0ed2076876..5f17dcace1f 100644 --- a/core/embed/models/D001/model_D001.h +++ b/core/embed/models/D001/model_D001.h @@ -22,8 +22,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_BLAKE2S -#define BOARD_CAPABILITIES_ADDR 0x0800BF00 -#define CODE_ALIGNMENT 0x200 +#define DISPLAY_JUMP_BEHAVIOR DISPLAY_RESET_CONTENT // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 @@ -31,6 +30,7 @@ #define BOOTLOADER_START 0x08020000 #define FIRMWARE_START 0x08040000 #define FIRMWARE_P2_START 0x08120000 +#define KERNEL_START 0x08040000 #define STORAGE_1_OFFSET 0x10000 #define STORAGE_2_OFFSET 0x110000 #define NORCOW_SECTOR_SIZE (1 * 64 * 1024) // 64 kB @@ -39,6 +39,7 @@ #define FIRMWARE_IMAGE_MAXSIZE (13 * 128 * 1024) // 1664 kB #define FIRMWARE_P1_IMAGE_MAXSIZE (6 * 128 * 1024) #define FIRMWARE_P2_IMAGE_MAXSIZE (7 * 128 * 1024) +#define KERNEL_IMAGE_MAXSIZE (4 * 128 * 1024) #define BOARDLOADER_SECTOR_START 0 #define BOARDLOADER_SECTOR_END 3 #define BOOTLOADER_SECTOR_START 5 @@ -51,5 +52,13 @@ #define STORAGE_1_SECTOR_END 4 #define STORAGE_2_SECTOR_START 16 #define STORAGE_2_SECTOR_END 16 +#define KERNEL_STACK_SIZE 8 * 1024 +#define KERNEL_CCMRAM_SIZE 16 * 1024 +#define KERNEL_FRAMEBUFFER_SIZE 0 * 1024 +#define KERNEL_SRAM_SIZE 1 * 1024 + +#define BOOTARGS_SIZE 0x100 +#define BOARD_CAPABILITIES_ADDR 0x0800BF00 +#define CODE_ALIGNMENT 0x200 #endif diff --git a/core/embed/models/D002/boards/stm32u5a9j-dk.h b/core/embed/models/D002/boards/stm32u5a9j-dk.h index baf3e711715..059fac72b06 100644 --- a/core/embed/models/D002/boards/stm32u5a9j-dk.h +++ b/core/embed/models/D002/boards/stm32u5a9j-dk.h @@ -30,6 +30,11 @@ #define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOH_CLK_ENABLE #define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR2 #define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR2_I2C5RST +#define I2C_INSTANCE_0_EV_IRQHandler I2C5_EV_IRQHandler +#define I2C_INSTANCE_0_ER_IRQHandler I2C5_ER_IRQHandler +#define I2C_INSTANCE_0_EV_IRQn I2C5_EV_IRQn +#define I2C_INSTANCE_0_ER_IRQn I2C5_ER_IRQn +#define I2C_INSTANCE_0_GUARD_TIME 0 #define TOUCH_I2C_INSTANCE 0 diff --git a/core/embed/models/D002/memory.ld b/core/embed/models/D002/memory.ld new file mode 100644 index 00000000000..aa927f05298 --- /dev/null +++ b/core/embed/models/D002/memory.ld @@ -0,0 +1,32 @@ +/* Auto-generated file, do not edit.*/ + +FLASH_START = 0xc000000; +BOARDLOADER_START = 0xc004000; +BOOTLOADER_START = 0xc010000; +KERNEL_START = 0xc050000; +FIRMWARE_START = 0xc050000; +STORAGE_1_OFFSET = 0x30000; +STORAGE_2_OFFSET = 0x40000; +NORCOW_SECTOR_SIZE = 0x10000; +BOARDLOADER_IMAGE_MAXSIZE = 0xc000; +BOOTLOADER_IMAGE_MAXSIZE = 0x20000; +FIRMWARE_IMAGE_MAXSIZE = 0x3a0000; +KERNEL_IMAGE_MAXSIZE = 0x80000; +BOARDLOADER_SECTOR_START = 0x2; +BOARDLOADER_SECTOR_END = 0x7; +BOOTLOADER_SECTOR_START = 0x8; +BOOTLOADER_SECTOR_END = 0x17; +FIRMWARE_SECTOR_START = 0x28; +FIRMWARE_SECTOR_END = 0x1f7; +STORAGE_1_SECTOR_START = 0x18; +STORAGE_1_SECTOR_END = 0x1f; +STORAGE_2_SECTOR_START = 0x20; +STORAGE_2_SECTOR_END = 0x27; +KERNEL_U_FLASH_SIZE = 0x200; +KERNEL_U_RAM_SIZE = 0x200; +KERNEL_SRAM1_SIZE = 0x4000; +KERNEL_SRAM2_SIZE = 0x2400; +KERNEL_SRAM3_SIZE = 0xbb800; +BOOTARGS_SIZE = 0x100; +BOARD_CAPABILITIES_ADDR = 0xc00ff00; +CODE_ALIGNMENT = 0x400; diff --git a/core/embed/models/D002/model_D002.h b/core/embed/models/D002/model_D002.h index 217974ca69f..25ec69810bc 100644 --- a/core/embed/models/D002/model_D002.h +++ b/core/embed/models/D002/model_D002.h @@ -25,20 +25,21 @@ #define IMAGE_CHUNK_SIZE SIZE_256K #define IMAGE_HASH_SHA256 -#define BOARD_CAPABILITIES_ADDR 0x0C00FF00 -#define CODE_ALIGNMENT 0x400 +#define DISPLAY_JUMP_BEHAVIOR DISPLAY_RESET_CONTENT -// SHARED WITH MAKEFILE +// SHARED WITH MAKEFILE, LINKER SCRIPT etc. #define FLASH_START 0x0C000000 #define BOARDLOADER_START 0x0C004000 #define BOOTLOADER_START 0x0C010000 +#define KERNEL_START 0x0C050000 #define FIRMWARE_START 0x0C050000 #define STORAGE_1_OFFSET 0x30000 -#define STORAGE_2_OFFSET 0x50000 +#define STORAGE_2_OFFSET 0x40000 #define NORCOW_SECTOR_SIZE (8 * 8 * 1024) // 64 kB #define BOARDLOADER_IMAGE_MAXSIZE (6 * 8 * 1024) // 48 kB #define BOOTLOADER_IMAGE_MAXSIZE (16 * 8 * 1024) // 128 kB #define FIRMWARE_IMAGE_MAXSIZE (464 * 8 * 1024) // 3712 kB +#define KERNEL_IMAGE_MAXSIZE (512 * 1024) // 512 kB #define BOARDLOADER_SECTOR_START 0x2 #define BOARDLOADER_SECTOR_END 0x7 #define BOOTLOADER_SECTOR_START 0x8 @@ -50,4 +51,14 @@ #define STORAGE_2_SECTOR_START 0x20 #define STORAGE_2_SECTOR_END 0x27 +#define KERNEL_U_FLASH_SIZE 512 +#define KERNEL_U_RAM_SIZE 512 +#define KERNEL_SRAM1_SIZE 16 * 1024 +#define KERNEL_SRAM2_SIZE 9 * 1024 +#define KERNEL_SRAM3_SIZE 750 * 1024 + +#define BOOTARGS_SIZE 0x100 +#define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define CODE_ALIGNMENT 0x400 + #endif diff --git a/core/embed/models/D002/model_D002_layout.c b/core/embed/models/D002/model_D002_layout.c index d1f3b48b107..4bb5eb8f9e5 100644 --- a/core/embed/models/D002/model_D002_layout.c +++ b/core/embed/models/D002/model_D002_layout.c @@ -77,20 +77,6 @@ const flash_area_t TRANSLATIONS_AREA = { }, }; -const flash_area_t WIPE_AREA = { - .num_subareas = 1, - .subarea[0] = - { - .first_sector = STORAGE_1_SECTOR_START, - .num_sectors = 488, - }, -}; - -const flash_area_t ALL_WIPE_AREA = { - .num_subareas = 1, - .subarea[0] = - { - .first_sector = BOOTLOADER_SECTOR_START, - .num_sectors = 504, - }, +const flash_area_t UNUSED_AREA = { + .num_subareas = 0, }; diff --git a/core/embed/models/T1B1/memory.ld b/core/embed/models/T1B1/memory.ld new file mode 100644 index 00000000000..1e78a10394f --- /dev/null +++ b/core/embed/models/T1B1/memory.ld @@ -0,0 +1,16 @@ +/* Auto-generated file, do not edit.*/ + +FLASH_START = 0x8000000; +BOOTLOADER_START = 0x8000000; +FIRMWARE_START = 0x8010000; +NORCOW_SECTOR_SIZE = 0x10000; +BOOTLOADER_IMAGE_MAXSIZE = 0x8000; +FIRMWARE_IMAGE_MAXSIZE = 0xf0000; +BOOTLOADER_SECTOR_START = 0x0; +BOOTLOADER_SECTOR_END = 0x2; +FIRMWARE_SECTOR_START = 0x4; +FIRMWARE_SECTOR_END = 0xb; +STORAGE_1_SECTOR_START = 0x2; +STORAGE_1_SECTOR_END = 0x2; +STORAGE_2_SECTOR_START = 0x3; +STORAGE_2_SECTOR_END = 0x3; diff --git a/core/embed/models/T1B1/model_T1B1.h b/core/embed/models/T1B1/model_T1B1.h index e5006b01e4d..ff007bc7575 100644 --- a/core/embed/models/T1B1/model_T1B1.h +++ b/core/embed/models/T1B1/model_T1B1.h @@ -12,6 +12,7 @@ #define IMAGE_CHUNK_SIZE (64 * 1024) #define IMAGE_HASH_SHA256 #define CODE_ALIGNMENT 0x200 +#define DISPLAY_JUMP_BEHAVIOR DISPLAY_RETAIN_CONTENT // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 diff --git a/core/embed/models/T2B1/boards/trezor_r_v10.h b/core/embed/models/T2B1/boards/trezor_r_v10.h index b48479d526b..24cda1e8ccf 100644 --- a/core/embed/models/T2B1/boards/trezor_r_v10.h +++ b/core/embed/models/T2B1/boards/trezor_r_v10.h @@ -50,7 +50,13 @@ #define I2C_INSTANCE_0_SCL_PORT GPIOB #define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_10 #define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE -#define I2C_INSTANCE_0_RESET_FLG RCC_APB1RSTR_I2C2RST +#define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR +#define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR_I2C2RST +#define I2C_INSTANCE_0_EV_IRQHandler I2C2_EV_IRQHandler +#define I2C_INSTANCE_0_ER_IRQHandler I2C2_ER_IRQHandler +#define I2C_INSTANCE_0_EV_IRQn I2C2_EV_IRQn +#define I2C_INSTANCE_0_ER_IRQn I2C2_ER_IRQn +#define I2C_INSTANCE_0_GUARD_TIME 50 // Optiga requires 50us guard time #define OPTIGA_I2C_INSTANCE 0 #define OPTIGA_RST_PORT GPIOD diff --git a/core/embed/models/T2B1/memory.ld b/core/embed/models/T2B1/memory.ld new file mode 100644 index 00000000000..3c841039f1d --- /dev/null +++ b/core/embed/models/T2B1/memory.ld @@ -0,0 +1,36 @@ +/* Auto-generated file, do not edit.*/ + +FLASH_START = 0x8000000; +BOARDLOADER_START = 0x8000000; +BOOTLOADER_START = 0x8020000; +FIRMWARE_START = 0x8040000; +FIRMWARE_P2_START = 0x8120000; +KERNEL_START = 0x8040000; +STORAGE_1_OFFSET = 0x10000; +STORAGE_2_OFFSET = 0x110000; +NORCOW_SECTOR_SIZE = 0x10000; +BOARDLOADER_IMAGE_MAXSIZE = 0xc000; +BOOTLOADER_IMAGE_MAXSIZE = 0x20000; +FIRMWARE_IMAGE_MAXSIZE = 0x1a0000; +FIRMWARE_P1_IMAGE_MAXSIZE = 0xc0000; +FIRMWARE_P2_IMAGE_MAXSIZE = 0xe0000; +KERNEL_IMAGE_MAXSIZE = 0x80000; +BOARDLOADER_SECTOR_START = 0x0; +BOARDLOADER_SECTOR_END = 0x3; +BOOTLOADER_SECTOR_START = 0x5; +BOOTLOADER_SECTOR_END = 0x5; +FIRMWARE_SECTOR_START = 0x6; +FIRMWARE_SECTOR_END = 0xb; +FIRMWARE_P2_SECTOR_START = 0x11; +FIRMWARE_P2_SECTOR_END = 0x17; +STORAGE_1_SECTOR_START = 0x4; +STORAGE_1_SECTOR_END = 0x4; +STORAGE_2_SECTOR_START = 0x10; +STORAGE_2_SECTOR_END = 0x10; +KERNEL_STACK_SIZE = 0x2000; +KERNEL_CCMRAM_SIZE = 0x4000; +KERNEL_FRAMEBUFFER_SIZE = 0x2000; +KERNEL_SRAM_SIZE = 0x400; +BOOTARGS_SIZE = 0x100; +BOARD_CAPABILITIES_ADDR = 0x800bf00; +CODE_ALIGNMENT = 0x200; diff --git a/core/embed/models/T2B1/model_T2B1.h b/core/embed/models/T2B1/model_T2B1.h index d82aefc89b0..74632ad2498 100644 --- a/core/embed/models/T2B1/model_T2B1.h +++ b/core/embed/models/T2B1/model_T2B1.h @@ -24,8 +24,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_BLAKE2S -#define BOARD_CAPABILITIES_ADDR 0x0800BF00 -#define CODE_ALIGNMENT 0x200 +#define DISPLAY_JUMP_BEHAVIOR DISPLAY_RETAIN_CONTENT // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 @@ -33,6 +32,7 @@ #define BOOTLOADER_START 0x08020000 #define FIRMWARE_START 0x08040000 #define FIRMWARE_P2_START 0x08120000 +#define KERNEL_START 0x08040000 #define STORAGE_1_OFFSET 0x10000 #define STORAGE_2_OFFSET 0x110000 #define NORCOW_SECTOR_SIZE (1 * 64 * 1024) // 64 kB @@ -41,6 +41,7 @@ #define FIRMWARE_IMAGE_MAXSIZE (13 * 128 * 1024) // 1664 kB #define FIRMWARE_P1_IMAGE_MAXSIZE (6 * 128 * 1024) #define FIRMWARE_P2_IMAGE_MAXSIZE (7 * 128 * 1024) +#define KERNEL_IMAGE_MAXSIZE (4 * 128 * 1024) #define BOARDLOADER_SECTOR_START 0 #define BOARDLOADER_SECTOR_END 3 #define BOOTLOADER_SECTOR_START 5 @@ -53,5 +54,13 @@ #define STORAGE_1_SECTOR_END 4 #define STORAGE_2_SECTOR_START 16 #define STORAGE_2_SECTOR_END 16 +#define KERNEL_STACK_SIZE 8 * 1024 +#define KERNEL_CCMRAM_SIZE 16 * 1024 +#define KERNEL_FRAMEBUFFER_SIZE 8 * 1024 +#define KERNEL_SRAM_SIZE 1 * 1024 + +#define BOOTARGS_SIZE 0x100 +#define BOARD_CAPABILITIES_ADDR 0x0800BF00 +#define CODE_ALIGNMENT 0x200 #endif diff --git a/core/embed/models/T2B1/model_T2B1_layout.c b/core/embed/models/T2B1/model_T2B1_layout.c index 430f4d49437..b4f510cc14e 100644 --- a/core/embed/models/T2B1/model_T2B1_layout.c +++ b/core/embed/models/T2B1/model_T2B1_layout.c @@ -74,21 +74,16 @@ const flash_area_t FIRMWARE_AREA = { }, }; -const flash_area_t WIPE_AREA = { - .num_subareas = 3, +const flash_area_t UNUSED_AREA = { + .num_subareas = 2, .subarea[0] = { - .first_sector = 4, + .first_sector = 3, .num_sectors = 1, }, .subarea[1] = { - .first_sector = 6, - .num_sectors = 6, - }, - .subarea[2] = - { - .first_sector = 16, - .num_sectors = 8, + .first_sector = 15, + .num_sectors = 1, }, }; diff --git a/core/embed/models/T2T1/boards/trezor_t.h b/core/embed/models/T2T1/boards/trezor_t.h index 14e2ffd3fff..60d569648b2 100644 --- a/core/embed/models/T2T1/boards/trezor_t.h +++ b/core/embed/models/T2T1/boards/trezor_t.h @@ -42,7 +42,13 @@ #define I2C_INSTANCE_0_SCL_PORT GPIOB #define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_6 #define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE -#define I2C_INSTANCE_0_RESET_FLG RCC_APB1RSTR_I2C1RST +#define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR +#define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR_I2C1RST +#define I2C_INSTANCE_0_EV_IRQHandler I2C1_EV_IRQHandler +#define I2C_INSTANCE_0_ER_IRQHandler I2C1_ER_IRQHandler +#define I2C_INSTANCE_0_EV_IRQn I2C1_EV_IRQn +#define I2C_INSTANCE_0_ER_IRQn I2C1_ER_IRQn +#define I2C_INSTANCE_0_GUARD_TIME 0 #define TOUCH_SENSITIVITY 0x06 #define TOUCH_I2C_INSTANCE 0 @@ -58,4 +64,11 @@ #define SD_ENABLE_PORT GPIOC #define SD_ENABLE_PIN GPIO_PIN_0 +// Ensure compatible hardware settings before jumping to +// the different booting stage. This function is used to +// ensure backward compatibility with older versions of +// released bootloaders and firmware. +#define ENSURE_COMPATIBLE_SETTINGS +extern void ensure_compatible_settings(void); + #endif //_TREZOR_T_H diff --git a/core/embed/models/T2T1/compat_settings.c b/core/embed/models/T2T1/compat_settings.c new file mode 100644 index 00000000000..a737b3c3760 --- /dev/null +++ b/core/embed/models/T2T1/compat_settings.c @@ -0,0 +1,4 @@ + +#include "platform.h" + +void ensure_compatible_settings(void) { set_core_clock(CLOCK_168_MHZ); } diff --git a/core/embed/models/T2T1/memory.ld b/core/embed/models/T2T1/memory.ld new file mode 100644 index 00000000000..abce5a3951c --- /dev/null +++ b/core/embed/models/T2T1/memory.ld @@ -0,0 +1,36 @@ +/* Auto-generated file, do not edit.*/ + +FLASH_START = 0x8000000; +BOARDLOADER_START = 0x8000000; +BOOTLOADER_START = 0x8020000; +FIRMWARE_START = 0x8040000; +FIRMWARE_P2_START = 0x8120000; +KERNEL_START = 0x8040000; +STORAGE_1_OFFSET = 0x10000; +STORAGE_2_OFFSET = 0x110000; +NORCOW_SECTOR_SIZE = 0x10000; +BOARDLOADER_IMAGE_MAXSIZE = 0xc000; +BOOTLOADER_IMAGE_MAXSIZE = 0x20000; +FIRMWARE_IMAGE_MAXSIZE = 0x1a0000; +FIRMWARE_P1_IMAGE_MAXSIZE = 0xc0000; +FIRMWARE_P2_IMAGE_MAXSIZE = 0xe0000; +KERNEL_IMAGE_MAXSIZE = 0x80000; +BOARDLOADER_SECTOR_START = 0x0; +BOARDLOADER_SECTOR_END = 0x3; +BOOTLOADER_SECTOR_START = 0x5; +BOOTLOADER_SECTOR_END = 0x5; +FIRMWARE_SECTOR_START = 0x6; +FIRMWARE_SECTOR_END = 0xb; +FIRMWARE_P2_SECTOR_START = 0x11; +FIRMWARE_P2_SECTOR_END = 0x17; +STORAGE_1_SECTOR_START = 0x4; +STORAGE_1_SECTOR_END = 0x4; +STORAGE_2_SECTOR_START = 0x10; +STORAGE_2_SECTOR_END = 0x10; +KERNEL_STACK_SIZE = 0x2000; +KERNEL_CCMRAM_SIZE = 0x4000; +KERNEL_FRAMEBUFFER_SIZE = 0x0; +KERNEL_SRAM_SIZE = 0x400; +BOOTARGS_SIZE = 0x100; +BOARD_CAPABILITIES_ADDR = 0x800bf00; +CODE_ALIGNMENT = 0x200; diff --git a/core/embed/models/T2T1/model_T2T1.h b/core/embed/models/T2T1/model_T2T1.h index fc29eaf94c2..a759fad7fc1 100644 --- a/core/embed/models/T2T1/model_T2T1.h +++ b/core/embed/models/T2T1/model_T2T1.h @@ -24,8 +24,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_BLAKE2S -#define BOARD_CAPABILITIES_ADDR 0x0800BF00 -#define CODE_ALIGNMENT 0x200 +#define DISPLAY_JUMP_BEHAVIOR DISPLAY_RETAIN_CONTENT // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 @@ -33,6 +32,7 @@ #define BOOTLOADER_START 0x08020000 #define FIRMWARE_START 0x08040000 #define FIRMWARE_P2_START 0x08120000 +#define KERNEL_START 0x08040000 #define STORAGE_1_OFFSET 0x10000 #define STORAGE_2_OFFSET 0x110000 #define NORCOW_SECTOR_SIZE (1 * 64 * 1024) // 64 kB @@ -41,6 +41,7 @@ #define FIRMWARE_IMAGE_MAXSIZE (13 * 128 * 1024) // 1664 kB #define FIRMWARE_P1_IMAGE_MAXSIZE (6 * 128 * 1024) #define FIRMWARE_P2_IMAGE_MAXSIZE (7 * 128 * 1024) +#define KERNEL_IMAGE_MAXSIZE (4 * 128 * 1024) #define BOARDLOADER_SECTOR_START 0 #define BOARDLOADER_SECTOR_END 3 #define BOOTLOADER_SECTOR_START 5 @@ -53,5 +54,13 @@ #define STORAGE_1_SECTOR_END 4 #define STORAGE_2_SECTOR_START 16 #define STORAGE_2_SECTOR_END 16 +#define KERNEL_STACK_SIZE 8 * 1024 +#define KERNEL_CCMRAM_SIZE 16 * 1024 +#define KERNEL_FRAMEBUFFER_SIZE 0 * 1024 +#define KERNEL_SRAM_SIZE 1 * 1024 + +#define BOOTARGS_SIZE 0x100 +#define BOARD_CAPABILITIES_ADDR 0x0800BF00 +#define CODE_ALIGNMENT 0x200 #endif diff --git a/core/embed/models/T2T1/model_T2T1_layout.c b/core/embed/models/T2T1/model_T2T1_layout.c index 091eebcf54a..aca5c3812f1 100644 --- a/core/embed/models/T2T1/model_T2T1_layout.c +++ b/core/embed/models/T2T1/model_T2T1_layout.c @@ -65,40 +65,25 @@ const flash_area_t FIRMWARE_AREA = { }, }; -const flash_area_t WIPE_AREA = { - .num_subareas = 3, +const flash_area_t SECRET_AREA = { + .num_subareas = 1, .subarea[0] = { - .first_sector = 4, - .num_sectors = 1, - }, - .subarea[1] = - { - .first_sector = 6, - .num_sectors = - 9, // sector 15 skipped due to bootloader MPU settings - }, - .subarea[2] = - { - .first_sector = 16, - .num_sectors = 8, + .first_sector = 0, + .num_sectors = 0, }, }; -const flash_area_t ALL_WIPE_AREA = { - .num_subareas = 1, +const flash_area_t UNUSED_AREA = { + .num_subareas = 2, .subarea[0] = { .first_sector = 3, - .num_sectors = 21, + .num_sectors = 1, }, -}; - -const flash_area_t SECRET_AREA = { - .num_subareas = 1, - .subarea[0] = + .subarea[1] = { - .first_sector = 0, - .num_sectors = 0, + .first_sector = 15, + .num_sectors = 1, }, }; diff --git a/core/embed/models/T3B1/boards/trezor_t3b1_revB.h b/core/embed/models/T3B1/boards/trezor_t3b1_revB.h index e91a2952d2a..7c57e7623d0 100644 --- a/core/embed/models/T3B1/boards/trezor_t3b1_revB.h +++ b/core/embed/models/T3B1/boards/trezor_t3b1_revB.h @@ -54,6 +54,11 @@ #define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOG_CLK_ENABLE #define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR1 #define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR1_I2C1RST +#define I2C_INSTANCE_0_EV_IRQHandler I2C1_EV_IRQHandler +#define I2C_INSTANCE_0_ER_IRQHandler I2C1_ER_IRQHandler +#define I2C_INSTANCE_0_EV_IRQn I2C1_EV_IRQn +#define I2C_INSTANCE_0_ER_IRQn I2C1_ER_IRQn +#define I2C_INSTANCE_0_GUARD_TIME 50 // Optiga requires 50us guard time #define OPTIGA_I2C_INSTANCE 0 #define OPTIGA_RST_PORT GPIOE diff --git a/core/embed/models/T3B1/memory.ld b/core/embed/models/T3B1/memory.ld new file mode 100644 index 00000000000..7a1ecab277b --- /dev/null +++ b/core/embed/models/T3B1/memory.ld @@ -0,0 +1,32 @@ +/* Auto-generated file, do not edit.*/ + +FLASH_START = 0xc000000; +BOARDLOADER_START = 0xc004000; +BOOTLOADER_START = 0xc010000; +KERNEL_START = 0xc050000; +FIRMWARE_START = 0xc050000; +STORAGE_1_OFFSET = 0x30000; +STORAGE_2_OFFSET = 0x40000; +NORCOW_SECTOR_SIZE = 0x10000; +BOARDLOADER_IMAGE_MAXSIZE = 0xc000; +BOOTLOADER_IMAGE_MAXSIZE = 0x20000; +FIRMWARE_IMAGE_MAXSIZE = 0x1a0000; +KERNEL_IMAGE_MAXSIZE = 0x80000; +BOARDLOADER_SECTOR_START = 0x2; +BOARDLOADER_SECTOR_END = 0x7; +BOOTLOADER_SECTOR_START = 0x8; +BOOTLOADER_SECTOR_END = 0x17; +FIRMWARE_SECTOR_START = 0x28; +FIRMWARE_SECTOR_END = 0xf7; +STORAGE_1_SECTOR_START = 0x18; +STORAGE_1_SECTOR_END = 0x1f; +STORAGE_2_SECTOR_START = 0x20; +STORAGE_2_SECTOR_END = 0x27; +KERNEL_U_FLASH_SIZE = 0x200; +KERNEL_U_RAM_SIZE = 0x200; +KERNEL_SRAM1_SIZE = 0x4000; +KERNEL_SRAM2_SIZE = 0x2000; +KERNEL_SRAM3_SIZE = 0x38400; +BOOTARGS_SIZE = 0x100; +BOARD_CAPABILITIES_ADDR = 0xc00ff00; +CODE_ALIGNMENT = 0x200; diff --git a/core/embed/models/T3B1/model_T3B1.h b/core/embed/models/T3B1/model_T3B1.h index 3e973c8ff57..d50bb4decde 100644 --- a/core/embed/models/T3B1/model_T3B1.h +++ b/core/embed/models/T3B1/model_T3B1.h @@ -25,20 +25,21 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_SHA256 -#define BOARD_CAPABILITIES_ADDR 0x0C00FF00 -#define CODE_ALIGNMENT 0x200 +#define DISPLAY_JUMP_BEHAVIOR DISPLAY_RETAIN_CONTENT -// SHARED WITH MAKEFILE +// SHARED WITH MAKEFILE, LINKER SCRIPT etc. #define FLASH_START 0x0C000000 #define BOARDLOADER_START 0x0C004000 #define BOOTLOADER_START 0x0C010000 +#define KERNEL_START 0x0C050000 #define FIRMWARE_START 0x0C050000 #define STORAGE_1_OFFSET 0x30000 -#define STORAGE_2_OFFSET 0x50000 +#define STORAGE_2_OFFSET 0x40000 #define NORCOW_SECTOR_SIZE (8 * 8 * 1024) // 64 kB #define BOARDLOADER_IMAGE_MAXSIZE (6 * 8 * 1024) // 48 kB #define BOOTLOADER_IMAGE_MAXSIZE (16 * 8 * 1024) // 128 kB #define FIRMWARE_IMAGE_MAXSIZE (208 * 8 * 1024) // 1664 kB +#define KERNEL_IMAGE_MAXSIZE (512 * 1024) // 512 kB #define BOARDLOADER_SECTOR_START 0x2 #define BOARDLOADER_SECTOR_END 0x7 #define BOOTLOADER_SECTOR_START 0x8 @@ -50,4 +51,14 @@ #define STORAGE_2_SECTOR_START 0x20 #define STORAGE_2_SECTOR_END 0x27 +#define KERNEL_U_FLASH_SIZE 512 +#define KERNEL_U_RAM_SIZE 512 +#define KERNEL_SRAM1_SIZE 16 * 1024 +#define KERNEL_SRAM2_SIZE 8 * 1024 +#define KERNEL_SRAM3_SIZE 0x38400 + +#define BOOTARGS_SIZE 0x100 +#define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define CODE_ALIGNMENT 0x200 + #endif diff --git a/core/embed/models/T3B1/model_T3B1_layout.c b/core/embed/models/T3B1/model_T3B1_layout.c index 3baae222edb..f776dfccaef 100644 --- a/core/embed/models/T3B1/model_T3B1_layout.c +++ b/core/embed/models/T3B1/model_T3B1_layout.c @@ -77,20 +77,6 @@ const flash_area_t TRANSLATIONS_AREA = { }, }; -const flash_area_t WIPE_AREA = { - .num_subareas = 1, - .subarea[0] = - { - .first_sector = STORAGE_1_SECTOR_START, - .num_sectors = 232, - }, -}; - -const flash_area_t ALL_WIPE_AREA = { - .num_subareas = 1, - .subarea[0] = - { - .first_sector = BOOTLOADER_SECTOR_START, - .num_sectors = 248, - }, +const flash_area_t UNUSED_AREA = { + .num_subareas = 0, }; diff --git a/core/embed/models/T3T1/boards/trezor_t3t1_revE.h b/core/embed/models/T3T1/boards/trezor_t3t1_revE.h index 591ff37b52b..425b9afc498 100644 --- a/core/embed/models/T3T1/boards/trezor_t3t1_revE.h +++ b/core/embed/models/T3T1/boards/trezor_t3t1_revE.h @@ -50,6 +50,11 @@ #define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE #define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR1 #define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR1_I2C1RST +#define I2C_INSTANCE_0_EV_IRQHandler I2C1_EV_IRQHandler +#define I2C_INSTANCE_0_ER_IRQHandler I2C1_ER_IRQHandler +#define I2C_INSTANCE_0_EV_IRQn I2C1_EV_IRQn +#define I2C_INSTANCE_0_ER_IRQn I2C1_ER_IRQn +#define I2C_INSTANCE_0_GUARD_TIME 0 #define I2C_INSTANCE_1 I2C2 #define I2C_INSTANCE_1_CLK_EN __HAL_RCC_I2C2_CLK_ENABLE @@ -63,6 +68,11 @@ #define I2C_INSTANCE_1_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE #define I2C_INSTANCE_1_RESET_REG &RCC->APB1RSTR1 #define I2C_INSTANCE_1_RESET_BIT RCC_APB1RSTR1_I2C2RST +#define I2C_INSTANCE_1_EV_IRQHandler I2C2_EV_IRQHandler +#define I2C_INSTANCE_1_ER_IRQHandler I2C2_ER_IRQHandler +#define I2C_INSTANCE_1_EV_IRQn I2C2_EV_IRQn +#define I2C_INSTANCE_1_ER_IRQn I2C2_ER_IRQn +#define I2C_INSTANCE_1_GUARD_TIME 0 #define I2C_INSTANCE_2 I2C3 #define I2C_INSTANCE_2_CLK_EN __HAL_RCC_I2C3_CLK_ENABLE @@ -76,6 +86,11 @@ #define I2C_INSTANCE_2_SCL_CLK_EN __HAL_RCC_GPIOC_CLK_ENABLE #define I2C_INSTANCE_2_RESET_REG &RCC->APB3RSTR #define I2C_INSTANCE_2_RESET_BIT RCC_APB3RSTR_I2C3RST +#define I2C_INSTANCE_2_EV_IRQHandler I2C3_EV_IRQHandler +#define I2C_INSTANCE_2_ER_IRQHandler I2C3_ER_IRQHandler +#define I2C_INSTANCE_2_EV_IRQn I2C3_EV_IRQn +#define I2C_INSTANCE_2_ER_IRQn I2C3_ER_IRQn +#define I2C_INSTANCE_2_GUARD_TIME 50 // Optiga requires 50us guard time #define TOUCH_PANEL_LX154A2422CPT23 1 #define TOUCH_SENSITIVITY 0x40 diff --git a/core/embed/models/T3T1/boards/trezor_t3t1_v4.h b/core/embed/models/T3T1/boards/trezor_t3t1_v4.h index bf2c0a00d8d..1a8741e0a5f 100644 --- a/core/embed/models/T3T1/boards/trezor_t3t1_v4.h +++ b/core/embed/models/T3T1/boards/trezor_t3t1_v4.h @@ -51,6 +51,11 @@ #define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE #define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR1 #define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR1_I2C1RST +#define I2C_INSTANCE_0_EV_IRQHandler I2C1_EV_IRQHandler +#define I2C_INSTANCE_0_ER_IRQHandler I2C1_ER_IRQHandler +#define I2C_INSTANCE_0_EV_IRQn I2C1_EV_IRQn +#define I2C_INSTANCE_0_ER_IRQn I2C1_ER_IRQn +#define I2C_INSTANCE_0_GUARD_TIME 0 #define I2C_INSTANCE_1 I2C2 #define I2C_INSTANCE_1_CLK_EN __HAL_RCC_I2C2_CLK_ENABLE @@ -64,6 +69,11 @@ #define I2C_INSTANCE_1_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE #define I2C_INSTANCE_1_RESET_REG &RCC->APB1RSTR1 #define I2C_INSTANCE_1_RESET_BIT RCC_APB1RSTR1_I2C2RST +#define I2C_INSTANCE_1_EV_IRQHandler I2C2_EV_IRQHandler +#define I2C_INSTANCE_1_ER_IRQHandler I2C2_ER_IRQHandler +#define I2C_INSTANCE_1_EV_IRQn I2C2_EV_IRQn +#define I2C_INSTANCE_1_ER_IRQn I2C2_ER_IRQn +#define I2C_INSTANCE_1_GUARD_TIME 50 // Optiga requires 50us guard time #define TOUCH_SENSITIVITY 0x40 #define TOUCH_I2C_INSTANCE 0 diff --git a/core/embed/models/T3T1/memory.ld b/core/embed/models/T3T1/memory.ld new file mode 100644 index 00000000000..7a1ecab277b --- /dev/null +++ b/core/embed/models/T3T1/memory.ld @@ -0,0 +1,32 @@ +/* Auto-generated file, do not edit.*/ + +FLASH_START = 0xc000000; +BOARDLOADER_START = 0xc004000; +BOOTLOADER_START = 0xc010000; +KERNEL_START = 0xc050000; +FIRMWARE_START = 0xc050000; +STORAGE_1_OFFSET = 0x30000; +STORAGE_2_OFFSET = 0x40000; +NORCOW_SECTOR_SIZE = 0x10000; +BOARDLOADER_IMAGE_MAXSIZE = 0xc000; +BOOTLOADER_IMAGE_MAXSIZE = 0x20000; +FIRMWARE_IMAGE_MAXSIZE = 0x1a0000; +KERNEL_IMAGE_MAXSIZE = 0x80000; +BOARDLOADER_SECTOR_START = 0x2; +BOARDLOADER_SECTOR_END = 0x7; +BOOTLOADER_SECTOR_START = 0x8; +BOOTLOADER_SECTOR_END = 0x17; +FIRMWARE_SECTOR_START = 0x28; +FIRMWARE_SECTOR_END = 0xf7; +STORAGE_1_SECTOR_START = 0x18; +STORAGE_1_SECTOR_END = 0x1f; +STORAGE_2_SECTOR_START = 0x20; +STORAGE_2_SECTOR_END = 0x27; +KERNEL_U_FLASH_SIZE = 0x200; +KERNEL_U_RAM_SIZE = 0x200; +KERNEL_SRAM1_SIZE = 0x4000; +KERNEL_SRAM2_SIZE = 0x2000; +KERNEL_SRAM3_SIZE = 0x38400; +BOOTARGS_SIZE = 0x100; +BOARD_CAPABILITIES_ADDR = 0xc00ff00; +CODE_ALIGNMENT = 0x200; diff --git a/core/embed/models/T3T1/model_T3T1.h b/core/embed/models/T3T1/model_T3T1.h index cbada112e44..c5424a7757d 100644 --- a/core/embed/models/T3T1/model_T3T1.h +++ b/core/embed/models/T3T1/model_T3T1.h @@ -25,20 +25,21 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_SHA256 -#define BOARD_CAPABILITIES_ADDR 0x0C00FF00 -#define CODE_ALIGNMENT 0x200 +#define DISPLAY_JUMP_BEHAVIOR DISPLAY_RETAIN_CONTENT -// SHARED WITH MAKEFILE +// SHARED WITH MAKEFILE, LINKER SCRIPT etc. #define FLASH_START 0x0C000000 #define BOARDLOADER_START 0x0C004000 #define BOOTLOADER_START 0x0C010000 +#define KERNEL_START 0x0C050000 #define FIRMWARE_START 0x0C050000 #define STORAGE_1_OFFSET 0x30000 -#define STORAGE_2_OFFSET 0x50000 +#define STORAGE_2_OFFSET 0x40000 #define NORCOW_SECTOR_SIZE (8 * 8 * 1024) // 64 kB #define BOARDLOADER_IMAGE_MAXSIZE (6 * 8 * 1024) // 48 kB #define BOOTLOADER_IMAGE_MAXSIZE (16 * 8 * 1024) // 128 kB #define FIRMWARE_IMAGE_MAXSIZE (208 * 8 * 1024) // 1664 kB +#define KERNEL_IMAGE_MAXSIZE (512 * 1024) // 512 kB #define BOARDLOADER_SECTOR_START 0x2 #define BOARDLOADER_SECTOR_END 0x7 #define BOOTLOADER_SECTOR_START 0x8 @@ -50,4 +51,14 @@ #define STORAGE_2_SECTOR_START 0x20 #define STORAGE_2_SECTOR_END 0x27 +#define KERNEL_U_FLASH_SIZE 512 +#define KERNEL_U_RAM_SIZE 512 +#define KERNEL_SRAM1_SIZE 16 * 1024 +#define KERNEL_SRAM2_SIZE 8 * 1024 +#define KERNEL_SRAM3_SIZE 0x38400 + +#define BOOTARGS_SIZE 0x100 +#define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define CODE_ALIGNMENT 0x200 + #endif diff --git a/core/embed/models/T3T1/model_T3T1_layout.c b/core/embed/models/T3T1/model_T3T1_layout.c index 3baae222edb..f776dfccaef 100644 --- a/core/embed/models/T3T1/model_T3T1_layout.c +++ b/core/embed/models/T3T1/model_T3T1_layout.c @@ -77,20 +77,6 @@ const flash_area_t TRANSLATIONS_AREA = { }, }; -const flash_area_t WIPE_AREA = { - .num_subareas = 1, - .subarea[0] = - { - .first_sector = STORAGE_1_SECTOR_START, - .num_sectors = 232, - }, -}; - -const flash_area_t ALL_WIPE_AREA = { - .num_subareas = 1, - .subarea[0] = - { - .first_sector = BOOTLOADER_SECTOR_START, - .num_sectors = 248, - }, +const flash_area_t UNUSED_AREA = { + .num_subareas = 0, }; diff --git a/core/embed/models/layout_common.h b/core/embed/models/layout_common.h index 318bf5abd46..7a9d72dc561 100644 --- a/core/embed/models/layout_common.h +++ b/core/embed/models/layout_common.h @@ -20,7 +20,6 @@ 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; -extern const flash_area_t WIPE_AREA; -extern const flash_area_t ALL_WIPE_AREA; +extern const flash_area_t UNUSED_AREA; #endif diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c index 2d35986e057..1fa330f2af4 100644 --- a/core/embed/prodtest/main.c +++ b/core/embed/prodtest/main.c @@ -25,23 +25,26 @@ #include STM32_HAL_H #include "board_capabilities.h" +#include "bootutils.h" #include "button.h" #include "common.h" #include "display.h" #include "display_draw.h" #include "display_utils.h" -#include "fault_handlers.h" #include "flash.h" #include "flash_otp.h" -#include "i2c.h" +#include "fwutils.h" +#include "image.h" #include "model.h" #include "mpu.h" #include "prodtest_common.h" #include "random_delays.h" +#include "rsod.h" #include "sbu.h" #include "sdcard.h" #include "secbool.h" -#include "supervise.h" +#include "system.h" +#include "systimer.h" #include "touch.h" #include "usb.h" #include "version.h" @@ -593,14 +596,19 @@ static void test_firmware_version(void) { } static uint32_t read_bootloader_version(void) { + uint32_t version = 0; + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_BOOTUPDATE); + const image_header *header = read_image_header( (const uint8_t *)BOOTLOADER_START, BOOTLOADER_IMAGE_MAGIC, 0xffffffff); - if (secfalse == header) { - return 0; + if (header != NULL) { + version = header->version; } - return header->version; + mpu_restore(mpu_mode); + return version; } static void test_bootloader_version(uint32_t version) { @@ -619,7 +627,7 @@ static void test_boardloader_version(const boardloader_version_t *version) { } static void test_wipe(void) { - invalidate_firmware(); + firmware_invalidate_header(); display_clear(); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY / 2 + 10, "WIPED", -1, FONT_BOLD, COLOR_WHITE, COLOR_BLACK); @@ -761,7 +769,7 @@ static void test_otp_write_device_variant(const char *args) { vcp_println("OK"); } -static void test_reboot(void) { svc_reboot(); } +static void test_reboot(void) { reboot(); } void cpuid_read(void) { uint32_t cpuid[3]; @@ -776,9 +784,10 @@ void cpuid_read(void) { #define BACKLIGHT_NORMAL 150 int main(void) { - display_reinit(); - display_orientation(0); - random_delays_init(); + system_init(&rsod_panic_handler); + + display_init(DISPLAY_JUMP_BEHAVIOR); + #ifdef STM32U5 secure_aes_init(); #endif @@ -791,9 +800,6 @@ int main(void) { #ifdef USE_BUTTON button_init(); #endif -#ifdef USE_I2C - i2c_init(); -#endif #ifdef USE_TOUCH touch_init(); #endif @@ -808,19 +814,12 @@ int main(void) { uint32_t bootloader_version = read_bootloader_version(); const boardloader_version_t *boardloader_version = read_boardloader_version(); - mpu_config_prodtest_initial(); - #ifdef USE_OPTIGA optiga_init(); optiga_open_application(); pair_optiga(); #endif - mpu_config_prodtest(); - fault_handlers_init(); - - drop_privileges(); - display_clear(); draw_welcome_screen(); diff --git a/core/embed/prodtest/memory_stm32u5a.ld b/core/embed/prodtest/memory_stm32u5a.ld deleted file mode 100644 index fa303b5d4f7..00000000000 --- a/core/embed/prodtest/memory_stm32u5a.ld +++ /dev/null @@ -1,127 +0,0 @@ -/* TREZORv2 firmware linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 - 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); -_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 */ -confidential_lma = LOADADDR(.confidential); -confidential_vma = ADDR(.confidential); -confidential_size = SIZEOF(.confidential); - -/* 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); -_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); -_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(1024) { - 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; /* Overflow causes UsageFault */ - } >SRAM2 - - .confidential : ALIGN(512) { - *(.confidential*); - . = 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 - - .boot_args : ALIGN(8) { - *(.boot_command*); - . = ALIGN(8); - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS -} diff --git a/core/embed/prodtest/startup_stm32f4.s b/core/embed/prodtest/startup_stm32f4.s deleted file mode 100644 index ad8bc096ee3..00000000000 --- a/core/embed/prodtest/startup_stm32f4.s +++ /dev/null @@ -1,46 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // setup environment for subsequent stage of code - ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM - ldr r2, =0 // r2 - the word-sized value to be written - bl memset_reg - - ldr r0, =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 - ldr r2, =0 // r2 - the word-sized value to be written - bl memset_reg - - ldr r0, =sram_start // r0 - point to beginning of SRAM - ldr r1, =sram_end // r1 - point to byte after the end of SRAM - ldr r2, =0 // r2 - the word-sized value to be written - bl memset_reg - - // 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 - - // 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/prodtest/startup_stm32u5.s b/core/embed/prodtest/startup_stm32u5.s deleted file mode 100644 index f37f5b09285..00000000000 --- a/core/embed/prodtest/startup_stm32u5.s +++ /dev/null @@ -1,72 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // set the stack protection - ldr r0, =_sstack - add r0, r0, #16 // padding - msr MSPLIM, r0 - - // 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 confidential data in from flash - ldr r0, =confidential_vma // dst addr - ldr r1, =confidential_lma // src addr - ldr r2, =confidential_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/main.c b/core/embed/reflash/main.c index b98a3bceb79..0e7ef455802 100644 --- a/core/embed/reflash/main.c +++ b/core/embed/reflash/main.c @@ -23,6 +23,7 @@ #include STM32_HAL_H +#include "bootutils.h" #include "common.h" #include "display.h" #include "display_draw.h" @@ -30,9 +31,12 @@ #include "image.h" #include "model.h" #include "rng.h" +#include "rsod.h" #include "sbu.h" #include "sdcard.h" #include "secbool.h" +#include "system.h" +#include "systimer.h" #include "terminal.h" #include "touch.h" @@ -42,7 +46,7 @@ static void progress_callback(int pos, int len) { term_printf("."); } -static void flash_from_sdcard(const flash_area_t* area, uint32_t source, +static void flash_from_sdcard(const flash_area_t *area, uint32_t source, uint32_t length) { static uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)]; @@ -68,6 +72,8 @@ static void flash_from_sdcard(const flash_area_t* area, uint32_t source, } int main(void) { + system_init(&rsod_panic_handler); + sdcard_init(); touch_init(); diff --git a/core/embed/reflash/memory_stm32f4.ld b/core/embed/reflash/memory_stm32f4.ld deleted file mode 100644 index 718b009385a..00000000000 --- a/core/embed/reflash/memory_stm32f4.ld +++ /dev/null @@ -1,81 +0,0 @@ -/* TREZORv2 firmware linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x08040000, LENGTH = 768K - CCMRAM (wal) : ORIGIN = 0x10000000, LENGTH = 64K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x1000FF00, LENGTH = 0x100 - SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 192K -} - -main_stack_base = ORIGIN(SRAM) + LENGTH(SRAM); /* 8-byte aligned full descending stack */ -_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 wipe memory */ -ccmram_start = ORIGIN(CCMRAM); -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); - -/* used by the startup code to wipe memory */ -sram_start = ORIGIN(SRAM); -sram_end = ORIGIN(SRAM) + LENGTH(SRAM); -_ram_start = sram_start; -_ram_end = sram_end; - -_codelen = SIZEOF(.flash) + SIZEOF(.data); -_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(512); - } >FLASH AT>FLASH - - .data : ALIGN(4) { - *(.data*); - . = ALIGN(512); - } >SRAM AT>FLASH - - .bss : ALIGN(4) { - *(.bss*); - . = ALIGN(4); - } >SRAM - - .heap : ALIGN(4) { - . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ - . = ABSOLUTE(sram_end - 16K); /* this explicitly sets the end of the heap effectively giving the stack at most 16K */ - } >SRAM - - .stack : ALIGN(8) { - . = 4K; /* this acts as a build time assertion that at least this much memory is available for stack use */ - } >SRAM - - .boot_args : ALIGN(8) { - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS -} diff --git a/core/embed/reflash/memory_stm32u58.ld b/core/embed/reflash/memory_stm32u58.ld deleted file mode 100644 index e00c0df10f1..00000000000 --- a/core/embed/reflash/memory_stm32u58.ld +++ /dev/null @@ -1,123 +0,0 @@ -/* TREZORv2 firmware linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 - SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K - SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K - SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ - SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ - SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K -} - -main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ -_sstack = ORIGIN(SRAM2); -_estack = main_stack_base; - -/* used by the startup code to populate variables used by the C code */ -data_lma = LOADADDR(.data); -data_vma = ADDR(.data); -data_size = SIZEOF(.data); - -/* used by the startup code to populate variables used by the C code */ -confidential_lma = LOADADDR(.confidential); -confidential_vma = ADDR(.confidential); -confidential_size = SIZEOF(.confidential); - -/* 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); - -_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); -_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; /* Overflow causes UsageFault */ - } >SRAM2 - - .confidential : ALIGN(512) { - *(.confidential*); - . = ALIGN(512); - } >SRAM2 AT>FLASH - - .fb : ALIGN(4) { - __fb_start = .; - *(.fb1*); - *(.fb2*); - *(.framebuffer_select*); - __fb_end = .; - . = ALIGN(4); - } >SRAM3 - - .boot_args : ALIGN(8) { - *(.boot_command*); - . = ALIGN(8); - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS -} diff --git a/core/embed/reflash/memory_stm32u5a.ld b/core/embed/reflash/memory_stm32u5a.ld deleted file mode 100644 index e03a321847c..00000000000 --- a/core/embed/reflash/memory_stm32u5a.ld +++ /dev/null @@ -1,128 +0,0 @@ -/* TREZORv2 firmware linker script */ - -ENTRY(reset_handler) - -MEMORY { - FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 - 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); -_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 */ -confidential_lma = LOADADDR(.confidential); -confidential_vma = ADDR(.confidential); -confidential_size = SIZEOF(.confidential); - -/* 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); - -_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); -_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(1024) { - 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; /* Overflow causes UsageFault */ - } >SRAM2 - - .confidential : ALIGN(512) { - *(.confidential*); - . = 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 - - .boot_args : ALIGN(8) { - *(.boot_command*); - . = ALIGN(8); - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS -} diff --git a/core/embed/reflash/startup_stm32u5.s b/core/embed/reflash/startup_stm32u5.s deleted file mode 100644 index f37f5b09285..00000000000 --- a/core/embed/reflash/startup_stm32u5.s +++ /dev/null @@ -1,72 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // set the stack protection - ldr r0, =_sstack - add r0, r0, #16 // padding - msr MSPLIM, r0 - - // 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 confidential data in from flash - ldr r0, =confidential_vma // dst addr - ldr r1, =confidential_lma // src addr - ldr r2, =confidential_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 6f2706e5552..4f438d77f37 100644 --- a/core/embed/rust/build.rs +++ b/core/embed/rust/build.rs @@ -14,6 +14,10 @@ fn main() { link_core_objects(); } +fn build_dir() -> String { + env::var("BUILD_DIR").expect("BUILD_DIR not defined") +} + const DEFAULT_BINDGEN_MACROS_COMMON: &[&str] = &[ "-I../unix", "-I../trezorhal/unix", @@ -94,14 +98,7 @@ fn generate_qstr_bindings() { is_global: false, }) // Pass in correct include paths. - .clang_args(&[ - "-I", - if is_firmware() { - "../../build/firmware" - } else { - "../../build/unix" - }, - ]) + .clang_args(&["-I", &build_dir()]) // Customize the standard types. .use_core() .ctypes_prefix("cty") @@ -127,6 +124,8 @@ fn generate_qstr_bindings() { fn prepare_bindings() -> bindgen::Builder { let mut bindings = bindgen::Builder::default(); + let build_dir_include = format!("-I{}", build_dir()); + let mut clang_args: Vec<&str> = Vec::new(); let bindgen_macros_env = env::var("BINDGEN_MACROS").ok(); @@ -142,12 +141,12 @@ fn prepare_bindings() -> bindgen::Builder { bindings = bindings.clang_args(["-DNEW_RENDERING"]); } + clang_args.push(&build_dir_include); + // Pass in correct include paths and defines. if is_firmware() { clang_args.push("-nostdinc"); - clang_args.push("-I../../build/firmware"); - // Append gcc-arm-none-eabi's include paths. let cc_output = Command::new("arm-none-eabi-gcc") .arg("-E") @@ -168,8 +167,6 @@ fn prepare_bindings() -> bindgen::Builder { .map(|s| format!("-I{}", s.trim())); bindings = bindings.clang_args(include_args); - } else { - clang_args.push("-I../../build/unix"); } bindings = bindings.clang_args(&clang_args); @@ -306,8 +303,9 @@ fn generate_trezorhal_bindings() { // model .allowlist_var("MODEL_INTERNAL_NAME") .allowlist_var("MODEL_FULL_NAME") - // common - .allowlist_var("HW_ENTROPY_DATA") + // entropy + .allowlist_var("HW_ENTROPY_LEN") + .allowlist_function("entropy_get") // secbool .allowlist_type("secbool") .must_use_type("secbool") @@ -401,9 +399,9 @@ fn generate_trezorhal_bindings() { .allowlist_function("random_uniform") // rgb led .allowlist_function("rgb_led_set_color") - // time - .allowlist_function("hal_delay") - .allowlist_function("hal_ticks_ms") + // systick + .allowlist_function("systick_delay_ms") + .allowlist_function("systick_ms") // toif .allowlist_type("toif_format_t") // dma2d diff --git a/core/embed/rust/rust_ui_common.h b/core/embed/rust/rust_ui_common.h index 11f03965a8b..6c8a8b7dec0 100644 --- a/core/embed/rust/rust_ui_common.h +++ b/core/embed/rust/rust_ui_common.h @@ -1,8 +1,7 @@ #include "common.h" -__attribute__((noreturn)) void error_shutdown_rust(const char* title, - const char* msg, - const char* footer); +void display_rsod_rust(const char* title, const char* message, + const char* footer); void screen_boot_stage_2(void); diff --git a/core/embed/rust/src/protobuf/defs.rs b/core/embed/rust/src/protobuf/defs.rs index cdae0d22f25..acf4165683d 100644 --- a/core/embed/rust/src/protobuf/defs.rs +++ b/core/embed/rust/src/protobuf/defs.rs @@ -109,24 +109,9 @@ struct NameDef { msg_offset: u16, } -#[cfg(target_arch = "arm")] macro_rules! proto_def_path { ($filename:expr) => { - concat!( - env!("CARGO_MANIFEST_DIR"), - "/../../build/firmware/rust/", - $filename - ) - }; -} -#[cfg(not(target_arch = "arm"))] -macro_rules! proto_def_path { - ($filename:expr) => { - concat!( - env!("CARGO_MANIFEST_DIR"), - "/../../build/unix/rust/", - $filename - ) + concat!(env!("BUILD_DIR"), "/rust/", $filename) }; } diff --git a/core/embed/rust/src/trezorhal/fatal_error.rs b/core/embed/rust/src/trezorhal/fatal_error.rs index 20c9692bbb9..dec821bd815 100644 --- a/core/embed/rust/src/trezorhal/fatal_error.rs +++ b/core/embed/rust/src/trezorhal/fatal_error.rs @@ -1,31 +1,28 @@ mod ffi { extern "C" { - // trezorhal/common.c - pub fn trezor_shutdown() -> !; + // error_handling.h + pub fn error_shutdown(msg: *const cty::c_char) -> !; } } -use crate::ui::{ - shape, - ui_features::{ModelUI, UIFeaturesCommon}, -}; +pub fn error_shutdown(msg: &str) -> ! { + const MAX_LEN: usize = 63; + let mut buffer: [u8; MAX_LEN + 1] = [0; MAX_LEN + 1]; -fn shutdown() -> ! { - unsafe { ffi::trezor_shutdown() } -} - -/// Shows an error message and shuts down the device. -pub fn error_shutdown(title: &str, msg: &str, footer: &str) -> ! { - // SAFETY: - // This is the only situation we are allowed use this function - // to allow nested calls to `run_with_bumps`/`render_on_display`, - // because after the error message is displayed, the application will - // shut down. - unsafe { shape::unlock_bumps_on_failure() }; + // Copy the message to the buffer + let msg_bytes = msg.as_bytes(); + let len = if msg_bytes.len() < MAX_LEN { + msg_bytes.len() + } else { + MAX_LEN + }; + buffer[..len].copy_from_slice(&msg_bytes[..len]); - ModelUI::screen_fatal_error(title, msg, footer); - ModelUI::backlight_on(); - shutdown() + unsafe { + // SAFETY: `buffer` is a valid null-terminated string + // and the function never returns. + ffi::error_shutdown(buffer.as_ptr() as *const cty::c_char); + } } /// Shows an error message on the screen and shuts down the device. @@ -46,7 +43,7 @@ pub fn __fatal_error(msg: &str, _file: &str, _line: u32) -> ! { dbg_println!("==="); } - error_shutdown("INTERNAL_ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); + error_shutdown(msg); } pub trait UnwrapOrFatalError { diff --git a/core/embed/rust/src/trezorhal/storage.rs b/core/embed/rust/src/trezorhal/storage.rs index 6bf44a3b716..2a7a94cacc5 100644 --- a/core/embed/rust/src/trezorhal/storage.rs +++ b/core/embed/rust/src/trezorhal/storage.rs @@ -97,10 +97,13 @@ pub type StorageResult = Result; /// This function must be called before any other storage function. pub fn init() { unsafe { + let mut entropy_data: [u8; ffi::HW_ENTROPY_LEN as usize] = + [0; ffi::HW_ENTROPY_LEN as usize]; + ffi::entropy_get(entropy_data.as_mut_ptr()); ffi::storage_init( Some(callback_wrapper), - ffi::HW_ENTROPY_DATA.as_ptr(), - ffi::HW_ENTROPY_DATA.len() as u16, + entropy_data.as_ptr(), + entropy_data.len() as u16, ); } } diff --git a/core/embed/rust/src/trezorhal/time.rs b/core/embed/rust/src/trezorhal/time.rs index 30c9454cb3f..8c4e1e55c12 100644 --- a/core/embed/rust/src/trezorhal/time.rs +++ b/core/embed/rust/src/trezorhal/time.rs @@ -3,11 +3,11 @@ use crate::time::Duration; use super::ffi; pub fn ticks_ms() -> u32 { - unsafe { ffi::hal_ticks_ms() as _ } + unsafe { ffi::systick_ms() as _ } } pub fn sleep(delay: Duration) { unsafe { - ffi::hal_delay(delay.to_millis() as _); + ffi::systick_delay_ms(delay.to_millis() as _); } } diff --git a/core/embed/rust/src/ui/api/common_c.rs b/core/embed/rust/src/ui/api/common_c.rs index ccbed0d3a35..7eafbef5aa5 100644 --- a/core/embed/rust/src/ui/api/common_c.rs +++ b/core/embed/rust/src/ui/api/common_c.rs @@ -10,19 +10,33 @@ use crate::ui::{ geometry::{Alignment2D, Point}, }; -use crate::{trezorhal::fatal_error, ui::util::from_c_str}; +#[cfg(feature = "new_rendering")] +use crate::ui::shape; + +use crate::ui::util::from_c_str; #[no_mangle] -extern "C" fn error_shutdown_rust( +extern "C" fn display_rsod_rust( title: *const cty::c_char, msg: *const cty::c_char, footer: *const cty::c_char, -) -> ! { +) { let title = unsafe { from_c_str(title) }.unwrap_or(""); let msg = unsafe { from_c_str(msg) }.unwrap_or(""); let footer = unsafe { from_c_str(footer) }.unwrap_or(""); - fatal_error::error_shutdown(title, msg, footer) + // SAFETY: + // This is the only situation we are allowed use this function + // to allow nested calls to `run_with_bumps`/`render_on_display`, + // because after the error message is displayed, the application will + // shut down. + #[cfg(feature = "new_rendering")] + unsafe { + shape::unlock_bumps_on_failure() + }; + + ModelUI::screen_fatal_error(title, msg, footer); + ModelUI::backlight_on(); } #[no_mangle] diff --git a/core/embed/rust/trezorhal.h b/core/embed/rust/trezorhal.h index 7dadc0abf4c..48ab14222f9 100644 --- a/core/embed/rust/trezorhal.h +++ b/core/embed/rust/trezorhal.h @@ -7,6 +7,7 @@ #include "display_draw.h" #include "dma2d.h" #include "dma2d_bitblt.h" +#include "entropy.h" #include "flash.h" #include "fonts/fonts.h" #include "gfx_bitblt.h" diff --git a/core/embed/trezorhal/applet.h b/core/embed/trezorhal/applet.h new file mode 100644 index 00000000000..5309e7b5d8a --- /dev/null +++ b/core/embed/trezorhal/applet.h @@ -0,0 +1,81 @@ +/* + * 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_APPLET_H +#define TREZORHAL_APPLET_H + +#include +#include + +#ifdef SYSCALL_DISPATCH + +#include "systask.h" + +// Applet entry point +typedef void (*applet_startup_t)(const char* args, uint32_t random); + +// Applet header found at the beginning of the applet binary +typedef struct { + // Stack area + uint32_t stack_start; + uint32_t stack_size; + // Applet entry point + applet_startup_t startup; +} applet_header_t; + +// Applet memory layout +typedef struct { + // Data area 1 + uint32_t data1_start; + uint32_t data1_size; + // Data area 2 + uint32_t data2_start; + uint32_t data2_size; + +} applet_layout_t; + +typedef struct { + // Points to the applet header found at the beginning of the applet binary + applet_header_t* header; + // Applet memory layout describing the memory areas + // the applet is allowed to use + applet_layout_t layout; + // Applet task + systask_t task; + + // + privileges + +} applet_t; + +// Initializes the applet structure +void applet_init(applet_t* applet, applet_header_t* header, + applet_layout_t* layout); + +// Resets the applet and prepares it for execution from its entry point. +// +// Applet does not start immediately, it needs to be scheduled by +// `systask_yield_to(&applet->task)` after calling this function. +// +// Returns `true` if the applet was successfully reset. +bool applet_reset(applet_t* applet, uint32_t cmd, const void* arg, + size_t arg_size); + +#endif // SYSCALL_DISPATCH + +#endif // TREZORHAL_APPLET_H diff --git a/core/embed/trezorhal/bg_copy.h b/core/embed/trezorhal/bg_copy.h index be40c254285..dac9383d79d 100644 --- a/core/embed/trezorhal/bg_copy.h +++ b/core/embed/trezorhal/bg_copy.h @@ -6,6 +6,8 @@ #include #include +#ifdef KERNEL_MODE + /** * Callback function invoked from the IRQ context * when the transfer is complete @@ -38,4 +40,6 @@ void bg_copy_wait(void); void bg_copy_abort(void); +#endif // KERNEL_MODE + #endif diff --git a/core/embed/trezorhal/board_capabilities.h b/core/embed/trezorhal/board_capabilities.h index 66a4c28f590..6bf820dfc9e 100644 --- a/core/embed/trezorhal/board_capabilities.h +++ b/core/embed/trezorhal/board_capabilities.h @@ -35,6 +35,8 @@ Last tag must be terminator or all space used. #include +#ifdef KERNEL_MODE + #define BOARD_CAPABILITIES_SIZE 256 #define CAPABILITIES_HEADER "TRZC" @@ -77,4 +79,6 @@ void parse_boardloader_capabilities(); const uint32_t get_board_name(); const boardloader_version_t* get_boardloader_version(); +#endif // KERNEL_MODE + #endif diff --git a/core/embed/trezorhal/boot_args.h b/core/embed/trezorhal/boot_args.h deleted file mode 100644 index 4236a42ae9c..00000000000 --- a/core/embed/trezorhal/boot_args.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef TREZORHAL_BOOT_ARGS_H -#define TREZORHAL_BOOT_ARGS_H - -#include -#include - -// Defines boot command for 'svc_reboot_to_bootloader()' function -typedef enum { - // Normal boot sequence - BOOT_COMMAND_NONE = 0x00000000, - // Stop and wait for further instructions - BOOT_COMMAND_STOP_AND_WAIT = 0x0FC35A96, - // Do not ask anything, install an upgrade - BOOT_COMMAND_INSTALL_UPGRADE = 0xFA4A5C8D, -} boot_command_t; - -// Maximum size boot_args array -#define BOOT_ARGS_MAX_SIZE (256 - 8) - -typedef union { - uint8_t raw[BOOT_ARGS_MAX_SIZE]; - - // firmware header hash, BOOT_COMMAND_INSTALL_UPGRADE - uint8_t hash[32]; - -} boot_args_t; - -// Sets boot command and arguments for the next reboot -// arguments have too respect boot_args_t structure layout -// (function can be called multiple times before reboting) -void bootargs_set(boot_command_t command, const void* args, size_t args_size); - -// Returns the last boot command set by bootargs_set_command() -boot_command_t bootargs_get_command(); - -// Returns the pointer to boot arguments -const boot_args_t* bootargs_get_args(); - -#endif // TREZORHAL_BOOT_ARGS_H diff --git a/core/embed/trezorhal/bootargs.h b/core/embed/trezorhal/bootargs.h new file mode 100644 index 00000000000..1cfc5b97e8c --- /dev/null +++ b/core/embed/trezorhal/bootargs.h @@ -0,0 +1,57 @@ +/* + * 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_BOOTARGS_H +#define TREZORHAL_BOOTARGS_H + +#include +#include + +// Defines boot command processed in bootloader on next reboot +typedef enum { + // Normal boot sequence + BOOT_COMMAND_NONE = 0x00000000, + // Stop and wait for further instructions + BOOT_COMMAND_STOP_AND_WAIT = 0x0FC35A96, + // Do not ask anything, install an upgrade + BOOT_COMMAND_INSTALL_UPGRADE = 0xFA4A5C8D, +} boot_command_t; + +// Maximum size boot_args array +#define BOOT_ARGS_MAX_SIZE (256 - 8) + +typedef union { + uint8_t raw[BOOT_ARGS_MAX_SIZE]; + + // firmware header hash, BOOT_COMMAND_INSTALL_UPGRADE + uint8_t hash[32]; + +} boot_args_t; + +// Configures the boot command and associated arguments for the next reboot. +// The arguments must adhere to the boot_args_t structure layout. +void bootargs_set(boot_command_t command, const void* args, size_t args_size); + +// Returns the last boot command saved during bootloader startup +boot_command_t bootargs_get_command(); + +// Returns the pointer to boot arguments +const boot_args_t* bootargs_get_args(); + +#endif // TREZORHAL_BOOTARGS_H diff --git a/core/embed/trezorhal/bootutils.h b/core/embed/trezorhal/bootutils.h new file mode 100644 index 00000000000..cd1e84dbaa9 --- /dev/null +++ b/core/embed/trezorhal/bootutils.h @@ -0,0 +1,49 @@ +/* + * 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_BOOTUTILS_H +#define TREZORHAL_BOOTUTILS_H + +#include +#include + +// Immediately resets the device and initiates the normal boot sequence. +void __attribute__((noreturn)) reboot(void); + +// Resets the device and enters the bootloader, +// halting there and waiting for further user instructions. +void __attribute__((noreturn)) reboot_to_bootloader(void); + +// Resets the device into the bootloader and automatically continues +// with the installation of new firmware (also known as an +// interaction-less upgrade). +// +// If the provided hash is NULL or invalid, the device will stop +// at the bootloader and will require user acknowledgment to proceed +// with the firmware installation. +void __attribute__((noreturn)) reboot_and_upgrade(const uint8_t hash[32]); + +// Allows the user to see the displayed error message and then +// safely shuts down the device (clears secrets, memory, etc.). +// +// This function is called when the device enters an +// unrecoverable error state. +void __attribute__((noreturn)) secure_shutdown(void); + +#endif // TREZORHAL_BOOTUTILS_H diff --git a/core/embed/trezorhal/button.h b/core/embed/trezorhal/button.h index f1389f7f4ee..fa54013bcb3 100644 --- a/core/embed/trezorhal/button.h +++ b/core/embed/trezorhal/button.h @@ -28,7 +28,12 @@ #define BTN_LEFT 0 #define BTN_RIGHT 1 +#ifdef KERNEL_MODE + void button_init(void); + +#endif + uint32_t button_read(void); char button_state_left(void); char button_state_right(void); diff --git a/core/embed/trezorhal/common.h b/core/embed/trezorhal/common.h index e42dcfd99ea..3c92580c84a 100644 --- a/core/embed/trezorhal/common.h +++ b/core/embed/trezorhal/common.h @@ -26,6 +26,7 @@ #include "error_handling.h" #include "platform.h" +#include "systick.h" #ifndef MIN_8bits #define MIN_8bits(a, b) \ @@ -52,18 +53,6 @@ }) #endif -void __attribute__((noreturn)) trezor_shutdown(void); - -void hal_delay(uint32_t ms); -uint32_t hal_ticks_ms(); -void hal_delay_us(uint16_t delay_us); - -void collect_hw_entropy(void); -#define HW_ENTROPY_LEN (12 + 32) -extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; - -// Invalidates firmware on the device -// Note: only works when write access to firmware area is enabled by MPU -void invalidate_firmware(void); +#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) #endif diff --git a/core/embed/trezorhal/consumption_mask.h b/core/embed/trezorhal/consumption_mask.h index d11fdabf9d3..fdf1abb95ff 100644 --- a/core/embed/trezorhal/consumption_mask.h +++ b/core/embed/trezorhal/consumption_mask.h @@ -1,9 +1,31 @@ +/* + * 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 CORE_CONSUMPTION_MASK_H #define CORE_CONSUMPTION_MASK_H -void consumption_mask_randomize(); +#ifdef KERNEL_MODE void consumption_mask_init(void); +void consumption_mask_randomize(); + +#endif + #endif // CORE_CONSUMPTION_MASK_H diff --git a/core/embed/trezorhal/display.h b/core/embed/trezorhal/display.h index 5e296a8f751..34def49aa44 100644 --- a/core/embed/trezorhal/display.h +++ b/core/embed/trezorhal/display.h @@ -63,7 +63,7 @@ int display_orientation(int degrees); int display_get_orientation(void); int display_backlight(int val); -void display_init(void); +void display_init_all(void); void display_reinit(void); void display_sync(void); void display_refresh(void); @@ -77,5 +77,30 @@ uint8_t *display_get_wr_addr(void); void display_shift_window(uint16_t pixels); uint16_t display_get_window_offset(void); +typedef enum { + // Clear the display content + DISPLAY_RESET_CONTENT, + // Keeps the display without any changes + DISPLAY_RETAIN_CONTENT +} display_content_mode_t; + +static inline void display_init(display_content_mode_t mode) { + if (mode == DISPLAY_RESET_CONTENT) { + display_init_all(); + } else { + display_reinit(); + } +} + +static inline void display_deinit(display_content_mode_t mode) { + +#ifdef TREZOR_MODEL_T + if (mode == DISPLAY_RESET_CONTENT) { + display_orientation(0); + } +#endif + display_finish_actions(); +} + #endif // NEW_RENDERING #endif // TREZORHAL_DISPLAY_H diff --git a/core/embed/trezorhal/unix/fault_handlers.c b/core/embed/trezorhal/entropy.h similarity index 77% rename from core/embed/trezorhal/unix/fault_handlers.c rename to core/embed/trezorhal/entropy.h index 1e7754849cc..c71d0aab4f0 100644 --- a/core/embed/trezorhal/unix/fault_handlers.c +++ b/core/embed/trezorhal/entropy.h @@ -17,6 +17,19 @@ * along with this program. If not, see . */ -#include +#ifndef TREZORHAL_ENTROPY_H +#define TREZORHAL_ENTROPY_H -void fault_handlers_init(void) {} +#include + +#ifdef KERNEL_MODE + +void entropy_init(void); + +#endif + +#define HW_ENTROPY_LEN (12 + 32) + +void entropy_get(uint8_t *buf); + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/fault_handlers.h b/core/embed/trezorhal/fault_handlers.h deleted file mode 100644 index 8372135f37c..00000000000 --- a/core/embed/trezorhal/fault_handlers.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef TREZORHAL_FAULT_HANDLERS_H -#define TREZORHAL_FAULT_HANDLERS_H - -// Initializes and enables fault handlers -void fault_handlers_init(void); - -#endif // TREZORHAL_FAULT_HANDLERS_H diff --git a/core/embed/trezorhal/flash.h b/core/embed/trezorhal/flash.h index 2918b11ee55..ae0169af788 100644 --- a/core/embed/trezorhal/flash.h +++ b/core/embed/trezorhal/flash.h @@ -23,11 +23,10 @@ #include #include +#include "flash_ll.h" #include "platform.h" #include "secbool.h" -#include "flash_ll.h" - void flash_init(void); #endif // TREZORHAL_FLASH_H diff --git a/core/embed/trezorhal/flash_otp.h b/core/embed/trezorhal/flash_otp.h index c3f8705ab4a..56d05a237a2 100644 --- a/core/embed/trezorhal/flash_otp.h +++ b/core/embed/trezorhal/flash_otp.h @@ -3,6 +3,8 @@ #include +#ifdef KERNEL_MODE + #define FLASH_OTP_NUM_BLOCKS 16 #define FLASH_OTP_BLOCK_SIZE 32 @@ -15,4 +17,6 @@ secbool __wur flash_otp_write(uint8_t block, uint8_t offset, secbool __wur flash_otp_lock(uint8_t block); secbool __wur flash_otp_is_locked(uint8_t block); +#endif // KERNEL_MODE + #endif // TREZORHAL_FLASH_OTP_H diff --git a/core/embed/trezorhal/fwutils.h b/core/embed/trezorhal/fwutils.h new file mode 100644 index 00000000000..f29bc5ff638 --- /dev/null +++ b/core/embed/trezorhal/fwutils.h @@ -0,0 +1,66 @@ +/* + * 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_FWUTILS_H +#define TREZORHAL_FWUTILS_H + +#include + +#include "secbool.h" + +// Callback function for firmware hash calculation. +typedef void (*firmware_hash_callback_t)(void* context, uint32_t progress, + uint32_t total); + +// Calculates hash of the firmware area. +// +// `challenge` is a optional pointer to the challenge data. +// `challenge_len` is the length of the challenge data (1..32). +// `hash` is a pointer to a buffer where the hash will be stored. +// `hash_len` is size of the buffer (must be at least 32). +// `callback` is an optional callback function that will be called during the +// hash calculation. +// `callback_context` is a pointer that will be passed to the callback function. +// +// Returns `sectrue` if the hash was calculated successfully, `secfalse` +// otherwise. +secbool firmware_calc_hash(const uint8_t* challenge, size_t challenge_len, + uint8_t* hash, size_t hash_len, + firmware_hash_callback_t callback, + void* callback_context); + +// Reads the firmware vendor string from the header in the firmware area. +// +// `buff` is a pointer to a buffer where the vendor string will be stored. +// `buff_size` is the length of the buffer (reserve at least 64 bytes). +// +// Returns `sectrue` if the vendor string was read successfully, `secfalse` +// otherwise. +secbool firmware_get_vendor(char* buff, size_t buff_size); + +#ifdef KERNEL_MODE + +// Invalidates the firmware by erasing the first 1KB of the firmware area. +// +// Note: only works when write access to firmware area is enabled by MPU +void firmware_invalidate_header(void); + +#endif // KERNEL_MODE + +#endif // TREZORHAL_FWUTILS_H diff --git a/core/embed/trezorhal/haptic.h b/core/embed/trezorhal/haptic.h index ca7223b6586..6cb60ee9bbf 100644 --- a/core/embed/trezorhal/haptic.h +++ b/core/embed/trezorhal/haptic.h @@ -30,6 +30,8 @@ typedef enum { HAPTIC_HOLD_TO_CONFIRM = 1, } haptic_effect_t; +#ifdef KERNEL_MODE + // Initializes the haptic driver // // The function initializes the GPIO pins and the hardware @@ -44,6 +46,8 @@ bool haptic_init(void); // haptic driver so the device can be eventually put into a low-power mode. void haptic_deinit(void); +#endif // KERNEL_MODE + // Enables or disables the haptic driver // // When the driver is disabled, it does not play any haptic effects diff --git a/core/embed/trezorhal/hash_processor.h b/core/embed/trezorhal/hash_processor.h index 1ebc9bb94da..66c85653b93 100644 --- a/core/embed/trezorhal/hash_processor.h +++ b/core/embed/trezorhal/hash_processor.h @@ -10,9 +10,13 @@ typedef struct { uint8_t buffer[HASH_SHA256_BUFFER_SIZE]; /*!< data being processed */ } hash_sha265_context_t; +#ifdef KERNEL_MODE + // Initialize the hash processor void hash_processor_init(void); +#endif + // Calculate SHA256 hash of data // for best performance, data should be 32-bit aligned - as this allows DMA to // be used diff --git a/core/embed/trezorhal/i2c_bus.h b/core/embed/trezorhal/i2c_bus.h new file mode 100644 index 00000000000..2296a4d2c4d --- /dev/null +++ b/core/embed/trezorhal/i2c_bus.h @@ -0,0 +1,189 @@ +/* + * 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_I2C_BUS_H +#define TREZORHAL_I2C_BUS_H + +#include +#include +#include + +#ifdef KERNEL_MODE + +// I2C bus abstraction +typedef struct i2c_bus i2c_bus_t; +// I2C packet (series of I2C operations) +typedef struct i2c_packet i2c_packet_t; +// I2C operation (single transfer) +typedef struct i2c_op i2c_op_t; + +// Completion callback +typedef void (*i2c_callback_t)(void* context, i2c_packet_t* packet); + +// I2C packet status +typedef enum { + I2C_STATUS_OK = 0, // Packet completed successfully + I2C_STATUS_PENDING = 1, // Packet is pending + I2C_STATUS_INVARG = 2, // Invalid packet/op parameters + I2C_STATUS_BUSY = 3, // Bus is busy + I2C_STATUS_TIMEOUT = 4, // Timeout occurred + I2C_STATUS_NACK = 5, // Device did not acknowledge + I2C_STATUS_ERROR = 6, // General error + I2C_STATUS_ABORTED = 7, // Packet was aborted + +} i2c_status_t; + +struct i2c_packet { + // Next packet in the driver queue + i2c_packet_t* next; + // I2C device address (7-bit address) + uint8_t address; + // Extra timeout (in milliseconds) added to the default timeout + // to finish each operation + uint16_t timeout; + // I2C_STATUS_xxx + i2c_status_t status; + // Number of operations + uint8_t op_count; + // Pointer to array of operations + i2c_op_t* ops; + // Completion callback function + i2c_callback_t callback; + // Callback context (user provided data) + void* context; +}; + +// I2C operation flags +#define I2C_FLAG_START 0x0001 // Generate START condition before the operation +#define I2C_FLAG_STOP 0x0002 // Generate STOP after the operation +#define I2C_FLAG_TX 0x0004 // Transmit data +#define I2C_FLAG_RX 0x0008 // Receive data +#define I2C_FLAG_EMBED 0x0010 // Embedded data (no reference) + +// I2C operation flags constraints: +// 1) I2C_FLAG_TX | I2C_FLAG_RX is not allowed +// 2) if I2C_FLAG_EMBED is set, size must be <= 4 + +struct i2c_op { + // I2C_FLAG_xxx + uint16_t flags; + // Number of bytes to transfer + uint16_t size; + // Data to read or write + union { + // Pointer to data (I2C_FLAG_EMBED is not set) + void* ptr; + // Embedded data (I2C_FLAG_EMBED is set) + uint8_t data[4]; + }; +}; + +// Acquires I2C bus reference by index (0..2 according to the model) +// +// Returns NULL if bus is not available or can't be initialized. +// +// If the bus was not acquired before, it will be initialized. +i2c_bus_t* i2c_bus_open(uint8_t bus_index); + +// Closes I2C bus handle +// +// After releasing the last bus reference, the bus will be deinitialized. +void i2c_bus_close(i2c_bus_t* bus); + +// Submits I2C packet to the bus +// +// After submitting the packet, the packet status will be set to +// I2C_STATUS_PENDING until the packet is completed. +// +// The caller must not modify the packet (or data pointed by the packet) +// until the packet is completed (callback is called or status +// is not I2C_STATUS_PENDING). +// +// Returns: +// I2C_STATUS_OK -- packet was successfully submitted +i2c_status_t i2c_bus_submit(i2c_bus_t* bus, i2c_packet_t* packet); + +// Aborts pending or queue packet +// +// Immediately after calling this function, the packet status will be +// set to I2C_STATUS_ABORTED and I2C driver will not access the packet anymore. +// +// If the packet is already completed, it does nothing. +// If the packet is queued it will be removed from the queue. +// If the packet is pending, it will be aborted. +// In any case completion callback will not be called. +void i2c_bus_abort(i2c_bus_t* bus, i2c_packet_t* packet); + +// Returns I2C packet status +// +// If the packet is not completed yet, it returns I2C_STATUS_PENDING. +i2c_status_t i2c_packet_status(const i2c_packet_t* packet); + +// Waits until I2C packet is completed and returns its final status +i2c_status_t i2c_packet_wait(const i2c_packet_t* packet); + +// Helper function to submit and wait for the packet +static inline i2c_status_t i2c_bus_submit_and_wait(i2c_bus_t* bus, + i2c_packet_t* packet) { + i2c_status_t status = i2c_bus_submit(bus, packet); + if (status == I2C_STATUS_OK) { + status = i2c_packet_wait(packet); + } + return status; +} + +/* +void example() { + + i2c_bus_t* bus = i2c_bus_open(DEVICE_I2C_INSTANCE); + + static uint8_t data_out; + + static i2c_op_t ops[] = { + { + .flags = I2C_FLAG_TX | I2C_FLAG_EMBED, + .size = 1, + .data = {0x01}, + }, + { + .flags = I2C_FLAG_RX, + .size = sizeof(data_out), + .ptr = &data_out, + }, + }; + + static i2c_packet_t pkt = { + .callback = NULL, + .context = NULL, + .address = DEVICE_I2C_ADDRESS, + .op_count = ARRAY_LENGTH(ops), + .ops = ops, + }; + + status = i2c_bus_submit(bus, &pkt); + + status = i2c_packet_wait(&pkt); + + i2c_bus_close(&bus); +} +*/ + +#endif // KERNEL_MODE + +#endif // TREZORHAL_I2C_BUS_H diff --git a/core/embed/trezorhal/lowlevel.h b/core/embed/trezorhal/lowlevel.h index 49757aeac94..7d6cf789163 100644 --- a/core/embed/trezorhal/lowlevel.h +++ b/core/embed/trezorhal/lowlevel.h @@ -22,6 +22,8 @@ #include "secbool.h" +#ifdef KERNEL_MODE + secbool flash_check_option_bytes(void); void flash_lock_option_bytes(void); void flash_unlock_option_bytes(void); @@ -31,4 +33,6 @@ void periph_init(void); secbool reset_flags_check(void); void reset_flags_reset(void); +#endif // KERNEL_MODE + #endif // __TREZORHAL_LOWLEVEL_H__ diff --git a/core/embed/trezorhal/monoctr.h b/core/embed/trezorhal/monoctr.h index 296b573dbfb..e6394583f11 100644 --- a/core/embed/trezorhal/monoctr.h +++ b/core/embed/trezorhal/monoctr.h @@ -20,6 +20,8 @@ #ifndef TREZORHAL_MONOCTR #define TREZORHAL_MONOCTR +#ifdef KERNEL_MODE + // Monoctr module provides monotonic counter functionality #define MONOCTR_MAX_VALUE 63 @@ -40,4 +42,6 @@ secbool monoctr_write(monoctr_type_t type, uint8_t value); // Read the current value of the monotonic counter secbool monoctr_read(monoctr_type_t type, uint8_t* value); +#endif // KERNEL_MODE + #endif diff --git a/core/embed/trezorhal/mpu.h b/core/embed/trezorhal/mpu.h index a4aa0372829..8729c62e8c7 100644 --- a/core/embed/trezorhal/mpu.h +++ b/core/embed/trezorhal/mpu.h @@ -17,15 +17,55 @@ * along with this program. If not, see . */ -#ifndef __MPU_H__ -#define __MPU_H__ - -void mpu_config_off(void); -void mpu_config_boardloader(void); -void mpu_config_bootloader(void); -void mpu_config_firmware_initial(void); -void mpu_config_firmware(void); -void mpu_config_prodtest_initial(void); -void mpu_config_prodtest(void); - -#endif +#ifndef TREZORHAL_MPU_H +#define TREZORHAL_MPU_H + +#ifdef KERNEL_MODE + +// The MPU driver can be set to on of the following modes. +// +// In each mode, the MPU is configured to allow access to specific +// memory regions. +// +// The `MPU_MODE_DEFAULT` mode is the most restrictive and serves as +// a base for other modes. +typedef enum { + MPU_MODE_DISABLED, // MPU is disabled + MPU_MODE_DEFAULT, // Default + MPU_MODE_BOARDCAPS, // + boardloader capabilities (privileged RO) + MPU_MODE_BOOTUPDATE, // + bootloader area (privileged RW) + MPU_MODE_OTP, // + OTP (privileged RW) + MPU_MODE_FSMC_REGS, // + FSMC control registers (privileged RW) + MPU_MODE_FLASHOB, // + Option bytes mapping (privileged RW) + MPU_MODE_SECRET, // + secret area (privileged RW) + MPU_MODE_STORAGE, // + both storage areas (privileged RW) + MPU_MODE_ASSETS, // + assets (privileged RW) + MPU_MODE_SAES, // + unprivileged SAES code + MPU_MODE_KERNEL_SRAM, // + extra kernel SRAM (STM32F4 Only) (privileged RW) + MPU_MODE_UNUSED_FLASH, // + unused flash areas (privileged RW) + MPU_MODE_APP, // + unprivileged DMA2D (RW) & Assets (RO) +} mpu_mode_t; + +// Initializes the MPU and sets it to MPU_MODE_DISABLED. +// +// This function should be called before any other MPU function. +void mpu_init(void); + +// Returns the current MPU mode. +// +// If the MPU is not initialized, returns MPU_MODE_DISABLED. +mpu_mode_t mpu_get_mode(void); + +// Reconfigures the MPU to the given mode and returns the previous mode. +// +// If the MPU is not initialized, does nothing and returns MPU_MODE_DISABLED. +mpu_mode_t mpu_reconfig(mpu_mode_t mode); + +// Restores the MPU to the given mode. +// +// Same as `mpu_reconfig()`, but with a more descriptive name. +void mpu_restore(mpu_mode_t mode); + +#endif // KERNEL_MODE + +#endif // TREZORHAL_MPU_H diff --git a/core/embed/trezorhal/optiga/optiga.c b/core/embed/trezorhal/optiga/optiga.c index 2189fc8dd92..d4fa2e2391a 100644 --- a/core/embed/trezorhal/optiga/optiga.c +++ b/core/embed/trezorhal/optiga/optiga.c @@ -27,6 +27,8 @@ #include "rand.h" #include "storage.h" +#ifdef KERNEL_MODE + // Counter-protected PIN secret and reset key for OID_STRETCHED_PIN_CTR (OID // 0xF1D0). #define OID_PIN_SECRET (OPTIGA_OID_DATA + 0) @@ -973,3 +975,5 @@ bool optiga_pin_decrease_rem(uint32_t count) { optiga_count_data_object(OID_STRETCHED_PIN_CTR, count) == OPTIGA_SUCCESS; } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/optiga/optiga_commands.c b/core/embed/trezorhal/optiga/optiga_commands.c index a77d7959151..1041adc887c 100644 --- a/core/embed/trezorhal/optiga/optiga_commands.c +++ b/core/embed/trezorhal/optiga/optiga_commands.c @@ -33,6 +33,8 @@ #include "optiga_transport.h" #include "sha2.h" +#ifdef KERNEL_MODE + // Static buffer for commands and responses. static uint8_t tx_buffer[OPTIGA_MAX_APDU_SIZE] = {0}; static size_t tx_size = 0; @@ -959,3 +961,5 @@ optiga_result optiga_set_priv_key(uint16_t oid, const uint8_t priv_key[32]) { return process_output_fixedlen(NULL, 0); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/optiga/optiga_transport.c b/core/embed/trezorhal/optiga/optiga_transport.c index 2d183f7b664..3ac1d820541 100644 --- a/core/embed/trezorhal/optiga/optiga_transport.c +++ b/core/embed/trezorhal/optiga/optiga_transport.c @@ -26,11 +26,13 @@ #include #include "aes/aesccm.h" #include "common.h" -#include "i2c.h" +#include "i2c_bus.h" #include "memzero.h" #include "optiga_hal.h" #include "tls_prf.h" +#ifdef KERNEL_MODE + #include TREZOR_BOARD // Maximum possible packet size that can be transmitted. @@ -58,9 +60,6 @@ static const uint8_t I2C_STATE_BYTE1_RESP_RDY = 0x40; // I2C base address of Optiga. static const uint8_t BASE_ADDR = 0x30; -// Address of Optiga use by our HAL which requires it to be shifted by one bit. -static const uint16_t OPTIGA_ADDRESS = (BASE_ADDR << 1); - // Constants for our I2C HAL. static const uint32_t I2C_TIMEOUT_MS = 25; static const int I2C_MAX_RETRY_COUNT = 10; @@ -110,6 +109,8 @@ enum { SCTR_PROTECTED = 0x23, // Record exchange message. Fully protected. }; +static i2c_bus_t *i2c_bus = NULL; + static uint8_t frame_num_out = 0xff; static uint8_t frame_num_in = 0xff; static uint8_t frame_buffer[1 + OPTIGA_DATA_REG_LEN]; @@ -190,35 +191,73 @@ static uint16_t calc_crc(uint8_t *data, size_t data_size) { optiga_result optiga_init(void) { optiga_hal_init(); + + i2c_bus = i2c_bus_open(OPTIGA_I2C_INSTANCE); + if (i2c_bus == NULL) { + return OPTIGA_ERR_I2C_OPEN; + } + return optiga_set_data_reg_len(OPTIGA_DATA_REG_LEN); } static optiga_result optiga_i2c_write(const uint8_t *data, uint16_t data_size) { OPTIGA_LOG(">>>", data, data_size) + i2c_op_t ops[] = { + { + .flags = I2C_FLAG_TX, + .size = data_size, + .ptr = (void *)data, + }, + }; + + i2c_packet_t pkt = { + .address = BASE_ADDR, + .timeout = I2C_TIMEOUT_MS, + .op_count = ARRAY_LENGTH(ops), + .ops = ops, + }; + for (int try_count = 0; try_count <= I2C_MAX_RETRY_COUNT; ++try_count) { if (try_count != 0) { - hal_delay(1); + systick_delay_ms(1); } - if (HAL_OK == i2c_transmit(OPTIGA_I2C_INSTANCE, OPTIGA_ADDRESS, - (uint8_t *)data, data_size, I2C_TIMEOUT_MS)) { - hal_delay_us(1000); + + if (I2C_STATUS_OK == i2c_bus_submit_and_wait(i2c_bus, &pkt)) { + systick_delay_ms(1); return OPTIGA_SUCCESS; } - hal_delay_us(1000); + + systick_delay_ms(1); } return OPTIGA_ERR_I2C_WRITE; } static optiga_result optiga_i2c_read(uint8_t *buffer, uint16_t buffer_size) { + i2c_op_t ops[] = { + { + .flags = I2C_FLAG_RX, + .size = buffer_size, + .ptr = buffer, + }, + }; + + i2c_packet_t pkt = { + .address = BASE_ADDR, + .timeout = I2C_TIMEOUT_MS, + .op_count = ARRAY_LENGTH(ops), + .ops = ops, + }; + for (int try_count = 0; try_count <= I2C_MAX_RETRY_COUNT; ++try_count) { - HAL_Delay(1); - if (HAL_OK == i2c_receive(OPTIGA_I2C_INSTANCE, OPTIGA_ADDRESS, buffer, - buffer_size, I2C_TIMEOUT_MS)) { + systick_delay_ms(1); + + if (I2C_STATUS_OK == i2c_bus_submit_and_wait(i2c_bus, &pkt)) { OPTIGA_LOG("<<<", buffer, buffer_size) return OPTIGA_SUCCESS; } } + return OPTIGA_ERR_I2C_READ; } @@ -775,3 +814,5 @@ optiga_result optiga_sec_chan_handshake(const uint8_t *secret, sec_chan_established = true; return OPTIGA_SUCCESS; } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/optiga_common.h b/core/embed/trezorhal/optiga_common.h index 1c1e24e67e6..21d74aed689 100644 --- a/core/embed/trezorhal/optiga_common.h +++ b/core/embed/trezorhal/optiga_common.h @@ -24,6 +24,7 @@ typedef enum _optiga_result { OPTIGA_SUCCESS = 0, // Operation completed successfully. + OPTIGA_ERR_I2C_OPEN, // HAL failed to open I2C driver. OPTIGA_ERR_I2C_WRITE, // HAL failed on I2C write. OPTIGA_ERR_I2C_READ, // HAL failed on I2C read. OPTIGA_ERR_BUSY, // Optiga is busy processing another command. diff --git a/core/embed/trezorhal/random_delays.h b/core/embed/trezorhal/random_delays.h index ae8e0073fb1..ecdd6d44bd5 100644 --- a/core/embed/trezorhal/random_delays.h +++ b/core/embed/trezorhal/random_delays.h @@ -17,17 +17,22 @@ * along with this program. If not, see . */ -#ifndef __TREZORHAL_RANDOM_DELAYS_H__ -#define __TREZORHAL_RANDOM_DELAYS_H__ +#ifndef TREZORHAL_RANDOM_DELAYS_H +#define TREZORHAL_RANDOM_DELAYS_H #include -void random_delays_init(void); +#ifdef KERNEL_MODE + +void rdi_init(void); void rdi_start(void); void rdi_stop(void); + +#endif + void rdi_refresh_session_delay(void); -void rdi_handler(uint32_t uw_tick); void wait_random(void); -#endif + +#endif // TREZORHAL_RANDOM_DELAYS_H diff --git a/core/embed/trezorhal/rgb_led.h b/core/embed/trezorhal/rgb_led.h index a342b9a8580..1ad62d9b80c 100644 --- a/core/embed/trezorhal/rgb_led.h +++ b/core/embed/trezorhal/rgb_led.h @@ -1,4 +1,33 @@ +/* + * 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_RGB_LED_H +#define TREZORHAL_RGB_LED_H + +#include + +#ifdef KERNEL_MODE void rgb_led_init(void); +#endif + void rgb_led_set_color(uint32_t color); + +#endif // TREZORHAL_RGB_LED_H diff --git a/core/embed/trezorhal/rng.h b/core/embed/trezorhal/rng.h index 083b2c15080..7c9dc69a18e 100644 --- a/core/embed/trezorhal/rng.h +++ b/core/embed/trezorhal/rng.h @@ -22,8 +22,14 @@ #include +#ifdef KERNEL_MODE + void rng_init(void); + uint32_t rng_read(const uint32_t previous, const uint32_t compare_previous); + +#endif // KERNEL_MODE + uint32_t rng_get(void); #endif diff --git a/core/embed/trezorhal/sdcard.h b/core/embed/trezorhal/sdcard.h index e2f1bf4b8ab..730b33210fd 100644 --- a/core/embed/trezorhal/sdcard.h +++ b/core/embed/trezorhal/sdcard.h @@ -52,8 +52,13 @@ // this is a fixed size and should not be changed #define SDCARD_BLOCK_SIZE (512) +#ifdef KERNEL_MODE + void sdcard_init(void); secbool __wur sdcard_power_on_unchecked(bool low_speed); + +#endif + secbool __wur sdcard_power_on(void); void sdcard_power_off(void); secbool __wur sdcard_is_present(void); diff --git a/core/embed/trezorhal/secret.h b/core/embed/trezorhal/secret.h index 8c85ac9e5a2..288e98f7f91 100644 --- a/core/embed/trezorhal/secret.h +++ b/core/embed/trezorhal/secret.h @@ -1,7 +1,11 @@ +#ifndef TREZORHAL_SECRET_H +#define TREZORHAL_SECRET_H #include #include "secbool.h" +#ifdef KERNEL_MODE + #define SECRET_HEADER_MAGIC "TRZS" #define SECRET_HEADER_LEN 16 #define SECRET_OPTIGA_KEY_OFFSET 16 @@ -14,11 +18,6 @@ #define SECRET_BHK_OFFSET (1024 * 8) #define SECRET_BHK_LEN 32 -// Checks if bootloader is locked, that is the secret storage contains optiga -// pairing secret on platforms where access to the secret storage cannot be -// restricted for unofficial firmware -secbool secret_bootloader_locked(void); - // Writes data to the secret storage void secret_write(const uint8_t* data, uint32_t offset, uint32_t len); @@ -70,3 +69,12 @@ void secret_bhk_regenerate(void); // Disables access to the secret storage until next reset, if possible // This function is called by the bootloader before starting the firmware void secret_prepare_fw(secbool allow_run_with_secret, secbool trust_all); + +#endif // KERNEL_MODE + +// Checks if bootloader is locked, that is the secret storage contains optiga +// pairing secret on platforms where access to the secret storage cannot be +// restricted for unofficial firmware +secbool secret_bootloader_locked(void); + +#endif // TREZORHAL_SECRET_H diff --git a/core/embed/trezorhal/secure_aes.h b/core/embed/trezorhal/secure_aes.h index 69eac50dc6c..9849e68c037 100644 --- a/core/embed/trezorhal/secure_aes.h +++ b/core/embed/trezorhal/secure_aes.h @@ -24,10 +24,12 @@ #include #include +// only some of the keys are supported depending on execution environment typedef enum { - SECURE_AES_KEY_DHUK, + SECURE_AES_KEY_DHUK_SP, // secure-privileged SECURE_AES_KEY_BHK, - SECURE_AES_KEY_XORK, + SECURE_AES_KEY_XORK_SP, // secure-privileged + SECURE_AES_KEY_XORK_SN, // secure-nonprivileged } secure_aes_keysel_t; // Initializes secure AES module diff --git a/core/embed/trezorhal/stm32f4/applet.c b/core/embed/trezorhal/stm32f4/applet.c new file mode 100644 index 00000000000..a36e2f9cf33 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/applet.c @@ -0,0 +1,73 @@ +/* + * 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 "applet.h" +#include "mpu.h" +#include "rng.h" +#include "systask.h" + +#ifdef SYSCALL_DISPATCH + +void applet_init(applet_t* applet, applet_header_t* header, + applet_layout_t* layout) { + memset(applet, 0, sizeof(applet_t)); + + applet->header = header; + applet->layout = *layout; +} + +static void applet_clear_memory(applet_t* applet) { + if (applet->layout.data1_size > 0) { + memset((void*)applet->layout.data1_start, 0, applet->layout.data1_size); + } + if (applet->layout.data2_size > 0) { + memset((void*)applet->layout.data2_start, 0, applet->layout.data2_size); + } +} + +bool applet_reset(applet_t* applet, uint32_t cmd, const void* arg, + size_t arg_size) { + // Clear all memory the applet is allowed to use + applet_clear_memory(applet); + + // Reset the applet task (stack pointer, etc.) + systask_init(&applet->task, applet->header->stack_start, + applet->header->stack_size); + + // Copy the arguments onto the applet stack + void* arg_copy = NULL; + if (arg != NULL && arg_size > 0) { + arg_copy = systask_push_data(&applet->task, arg, arg_size); + if (arg_copy == NULL) { + return false; + } + } + + // Schedule the applet task run + uint32_t arg1 = cmd; + uint32_t arg2 = (uint32_t)arg_copy; + uint32_t arg3 = rng_get(); + + return systask_push_call(&applet->task, applet->header->startup, arg1, arg2, + arg3); +} + +#endif // SYSCALL_DISPATCH diff --git a/core/embed/trezorhal/stm32f4/backlight_pwm.c b/core/embed/trezorhal/stm32f4/backlight_pwm.c index a65e84e0fbe..47d88000b15 100644 --- a/core/embed/trezorhal/stm32f4/backlight_pwm.c +++ b/core/embed/trezorhal/stm32f4/backlight_pwm.c @@ -198,28 +198,38 @@ void backlight_pwm_deinit(backlight_action_t action) { return; } - if (action == BACKLIGHT_RETAIN) { - // We keep both the GPIO and the timer running - #ifdef TREZOR_MODEL_T - // This code here is for backward compatibility with the old - // bootloader that used a different PWM settings. + // This code is for backward compatibility with the older + // bootloader/firmware on model T that used different + // PWM settings and relies on proper settings from the + // previous stage during boot. // about 10Hz (with PSC = (SystemCoreClock / 1000000) - 1) #define LED_PWM_SLOW_TIM_PERIOD (10000) #define LED_PWM_PRESCALER_SLOW (SystemCoreClock / 1000000 - 1) // 1 MHz - BACKLIGHT_PWM_TIM->PSC = LED_PWM_PRESCALER_SLOW; - BACKLIGHT_PWM_TIM->CR1 |= TIM_CR1_ARPE; - BACKLIGHT_PWM_TIM->CR2 |= TIM_CR2_CCPC; - BACKLIGHT_PWM_TIM->ARR = LED_PWM_SLOW_TIM_PERIOD - 1; + BACKLIGHT_PWM_TIM->PSC = LED_PWM_PRESCALER_SLOW; + BACKLIGHT_PWM_TIM->CR1 |= TIM_CR1_ARPE; + BACKLIGHT_PWM_TIM->CR2 |= TIM_CR2_CCPC; + BACKLIGHT_PWM_TIM->ARR = LED_PWM_SLOW_TIM_PERIOD - 1; + + if (action == BACKLIGHT_RESET) { + BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = 0; + } else { // action == BACKLIGHT_RETAIN BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = (LED_PWM_SLOW_TIM_PERIOD * drv->current_level) / 255; -#endif - } else { - // TODO: deinitialize GPIOs and the TIMER } +#else + if (action == BACKLIGHT_RESET) { + // TODO: reset TIMER and GPIO + BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = 0; + } else { // action == BACKLIGHT_RETAIN + BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = + (LED_PWM_TIM_PERIOD * drv->current_level) / 255; + } +#endif + drv->initialized = false; } diff --git a/core/embed/trezorhal/stm32f4/board_capabilities.c b/core/embed/trezorhal/stm32f4/board_capabilities.c index c867c87cdc5..68757bbe9ee 100644 --- a/core/embed/trezorhal/stm32f4/board_capabilities.c +++ b/core/embed/trezorhal/stm32f4/board_capabilities.c @@ -17,10 +17,14 @@ * along with this program. If not, see . */ -#include "board_capabilities.h" #include + +#include "board_capabilities.h" #include "common.h" #include "model.h" +#include "mpu.h" + +#ifdef KERNEL_MODE static uint32_t board_name = 0; @@ -33,11 +37,14 @@ const boardloader_version_t *get_boardloader_version() { } void parse_boardloader_capabilities() { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_BOARDCAPS); + const uint8_t *pos = (const uint8_t *)BOARD_CAPABILITIES_ADDR; const uint8_t *end = (const uint8_t *)(BOARD_CAPABILITIES_ADDR + BOARD_CAPABILITIES_SIZE); if (memcmp(pos, CAPABILITIES_HEADER, 4) != 0) { + mpu_restore(mpu_mode); return; } @@ -70,6 +77,7 @@ void parse_boardloader_capabilities() { memcpy(&boardloader_version, pos, length); break; case TAG_TERMINATOR: + mpu_restore(mpu_mode); return; default: break; @@ -77,4 +85,8 @@ void parse_boardloader_capabilities() { pos += length; } + + mpu_restore(mpu_mode); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/boot_args.c b/core/embed/trezorhal/stm32f4/boot_args.c deleted file mode 100644 index 70caf21fc6d..00000000000 --- a/core/embed/trezorhal/stm32f4/boot_args.c +++ /dev/null @@ -1,44 +0,0 @@ - -#include "../boot_args.h" -#include -#include - -// The 'g_boot_command_shadow' shadows a real boot command passed -// to the bootloader. -// 1. In the bootloader, its value is set in the startup code. -// 2. In the firmware it holds command for the next boot and it is used -// when svc_reboot_to_bootloader() is called -boot_command_t g_boot_command_shadow; - -#ifdef STM32U5 -// The 'g_boot_command' is persistent variable that holds the 'command' -// for the next reboot/jump to the bootloader. Its value is set to -// g_boot_command_shadow when 'svc_reboot_to_bootloader()' is called. -boot_command_t __attribute__((section(".boot_command"))) g_boot_command; -#endif - -// The 'g_boot_args' is persistent array that stores extra arguments passed -// to the function bootargs_set. -static boot_args_t __attribute__((section(".boot_args"))) g_boot_args; - -void bootargs_set(boot_command_t command, const void* args, size_t args_size) { - // save boot command - g_boot_command_shadow = command; - - size_t copy_size = 0; - // copy arguments up to BOOT_ARGS_MAX_SIZE - if (args != NULL && args_size > 0) { - copy_size = MIN(args_size, BOOT_ARGS_MAX_SIZE); - memcpy(&g_boot_args.raw[0], args, copy_size); - } - - // clear rest of boot_args array - size_t clear_size = BOOT_ARGS_MAX_SIZE - copy_size; - if (clear_size > 0) { - memset(&g_boot_args.raw[copy_size], 0, clear_size); - } -} - -boot_command_t bootargs_get_command() { return g_boot_command_shadow; } - -const boot_args_t* bootargs_get_args() { return &g_boot_args; } diff --git a/core/embed/trezorhal/stm32f4/bootutils.c b/core/embed/trezorhal/stm32f4/bootutils.c new file mode 100644 index 00000000000..4e573905623 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/bootutils.c @@ -0,0 +1,139 @@ +/* + * 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 "bootargs.h" +#include "bootutils.h" +#include "common.h" +#include "display.h" +#include "image.h" +#include "irq.h" +#include "model.h" +#include "mpu.h" + +#ifdef KERNEL_MODE + +#ifdef STM32U5 +// Persistent variable that holds the 'command' for the next reboot. +boot_command_t __attribute__((section(".boot_command"))) g_boot_command; +#else +// Holds the 'command' for the next jump to the bootloader. +static boot_command_t g_boot_command = BOOT_COMMAND_NONE; +#endif + +// Persistent array that holds extra arguments for the command passed +// to the bootloader. +static boot_args_t __attribute__((section(".boot_args"))) g_boot_args; + +void bootargs_set(boot_command_t command, const void* args, size_t args_size) { + // save boot command + g_boot_command = command; + + size_t copy_size = 0; + // copy arguments up to BOOT_ARGS_MAX_SIZE + if (args != NULL && args_size > 0) { + copy_size = MIN(args_size, BOOT_ARGS_MAX_SIZE); + memcpy(&g_boot_args.raw[0], args, copy_size); + } + + // clear rest of boot_args array + size_t clear_size = BOOT_ARGS_MAX_SIZE - copy_size; + if (clear_size > 0) { + memset(&g_boot_args.raw[copy_size], 0, clear_size); + } +} + +#ifdef BOOTLOADER +// Contains the current boot command saved during bootloader startup. +boot_command_t g_boot_command_saved; + +boot_command_t bootargs_get_command() { return g_boot_command_saved; } + +const boot_args_t* bootargs_get_args() { return &g_boot_args; } +#endif + +// Deletes all secrets and SRAM2 where stack is located +// to prevent stack smashing error, do not return from function calling this +#ifdef STM32U5 +static inline void __attribute__((always_inline)) delete_secrets(void) { + __disable_irq(); + + // Disable SAES peripheral clock, so that we don't get tamper events + __HAL_RCC_SAES_CLK_DISABLE(); + + TAMP->CR2 |= TAMP_CR2_BKERASE; +} +#endif // STM32U5 + +// Reboots the device with the given boot command and arguments +static void __attribute__((noreturn)) +reboot_with_args(boot_command_t command, const void* args, size_t args_size) { + bootargs_set(command, args, args_size); + +#ifdef STM32U5 + delete_secrets(); + NVIC_SystemReset(); +#else + display_deinit(DISPLAY_RESET_CONTENT); +#ifdef ENSURE_COMPATIBLE_SETTINGS + ensure_compatible_settings(); +#endif + + mpu_reconfig(MPU_MODE_DISABLED); + + jump_to_with_flag(BOOTLOADER_START + IMAGE_HEADER_SIZE, g_boot_command); + for (;;) + ; +#endif +} + +void reboot_to_bootloader(void) { + reboot_with_args(BOOT_COMMAND_STOP_AND_WAIT, NULL, 0); +} + +void reboot_and_upgrade(const uint8_t hash[32]) { + reboot_with_args(BOOT_COMMAND_INSTALL_UPGRADE, hash, 32); +} + +void reboot(void) { + bootargs_set(BOOT_COMMAND_NONE, NULL, 0); + +#ifdef STM32U5 + delete_secrets(); +#endif + + NVIC_SystemReset(); +} + +void __attribute__((noreturn)) secure_shutdown(void) { + display_deinit(DISPLAY_RETAIN_CONTENT); + +#ifdef STM32U5 + delete_secrets(); +#endif + // from util.s + extern void shutdown_privileged(void); + shutdown_privileged(); + + for (;;) + ; +} + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/button.c b/core/embed/trezorhal/stm32f4/button.c index b8ca256b7f2..544b8ba4824 100644 --- a/core/embed/trezorhal/stm32f4/button.c +++ b/core/embed/trezorhal/stm32f4/button.c @@ -2,6 +2,8 @@ #include "button.h" #include TREZOR_BOARD +#ifdef KERNEL_MODE + static char last_left = 0, last_right = 0; void button_init(void) { @@ -45,3 +47,5 @@ uint32_t button_read(void) { char button_state_left(void) { return last_left; } char button_state_right(void) { return last_right; } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/common.c b/core/embed/trezorhal/stm32f4/common.c index 88c397c27c8..7ac11fe6acb 100644 --- a/core/embed/trezorhal/stm32f4/common.c +++ b/core/embed/trezorhal/stm32f4/common.c @@ -23,12 +23,12 @@ #include "common.h" #include "display.h" +#include "error_handling.h" #include "model.h" #include "flash_otp.h" #include "platform.h" #include "rand.h" -#include "supervise.h" #include "stm32f4xx_ll_utils.h" @@ -36,37 +36,7 @@ #include "backlight_pwm.h" #endif -uint32_t systick_val_copy = 0; - -// from util.s -extern void shutdown_privileged(void); - -void __attribute__((noreturn)) trezor_shutdown(void) { - display_finish_actions(); -#ifdef USE_SVC_SHUTDOWN - svc_shutdown(); -#else - // It won't work properly unless called from the privileged mode - shutdown_privileged(); -#endif - - for (;;) - ; -} - -void hal_delay(uint32_t ms) { HAL_Delay(ms); } -uint32_t hal_ticks_ms() { return HAL_GetTick(); } -void hal_delay_us(uint16_t delay_us) { - uint32_t val = svc_get_systick_val(); - uint32_t t = hal_ticks_ms() * 1000 + - (((SystemCoreClock / 1000) - val) / (SystemCoreClock / 1000000)); - uint32_t t2 = t; - do { - val = svc_get_systick_val(); - t2 = hal_ticks_ms() * 1000 + - (((SystemCoreClock / 1000) - val) / (SystemCoreClock / 1000000)); - } while ((t2 - t) < delay_us); -} +#ifdef KERNEL_MODE // reference RM0090 section 35.12.1 Figure 413 #define USB_OTG_HS_DATA_FIFO_RAM (USB_OTG_HS_PERIPH_BASE + 0x20000U) @@ -85,61 +55,4 @@ void clear_otg_hs_memory(void) { // the peripheral is not needed right now } -uint32_t __stack_chk_guard = 0; - -void __attribute__((noreturn)) __stack_chk_fail(void) { - error_shutdown("(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) { -#ifdef TREZOR_MODEL_T -#ifdef NEW_RENDERING - display_set_compatible_settings(); -#else - display_set_big_endian(); -#endif - display_orientation(0); - set_core_clock(CLOCK_168_MHZ); - backlight_pwm_deinit(BACKLIGHT_RETAIN); -#endif -} - -void invalidate_firmware(void) { - // erase start of the firmware (metadata) -> invalidate FW - ensure(flash_unlock_write(), NULL); - for (int i = 0; i < (1024 / FLASH_BLOCK_SIZE); i += FLASH_BLOCK_SIZE) { - flash_block_t data = {0}; - ensure(flash_area_write_block(&FIRMWARE_AREA, i * FLASH_BLOCK_SIZE, data), - NULL); - } - ensure(flash_lock_write(), NULL); -} +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/consumption_mask.c b/core/embed/trezorhal/stm32f4/consumption_mask.c index 1da81915083..7263377d722 100644 --- a/core/embed/trezorhal/stm32f4/consumption_mask.c +++ b/core/embed/trezorhal/stm32f4/consumption_mask.c @@ -18,8 +18,11 @@ */ #include STM32_HAL_H +#include "mpu.h" #include "rng.h" +#ifdef KERNEL_MODE + #define SAMPLES 110 #define TIMER_PERIOD 16640 // cca 10 KHz @ 180MHz @@ -27,15 +30,16 @@ #error Not implemented for boardloader! #endif -#if defined BOOTLOADER -__attribute__((section(".buf"))) -#endif -uint32_t pwm_data[SAMPLES] = {0}; +__attribute__((section(".buf"))) uint32_t pwm_data[SAMPLES] = {0}; void consumption_mask_randomize() { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_KERNEL_SRAM); + for (int i = 0; i < SAMPLES; i++) { pwm_data[i] = rng_get() % TIMER_PERIOD; } + + mpu_restore(mpu_mode); } void consumption_mask_init(void) { @@ -106,3 +110,5 @@ void consumption_mask_init(void) { HAL_TIM_Base_Start(&TIM8_Handle); HAL_TIM_PWM_Start(&TIM8_Handle, TIM_CHANNEL_1); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/displays/ltdc.c b/core/embed/trezorhal/stm32f4/displays/ltdc.c index 93ee9659e2f..515106e74ab 100644 --- a/core/embed/trezorhal/stm32f4/displays/ltdc.c +++ b/core/embed/trezorhal/stm32f4/displays/ltdc.c @@ -221,7 +221,7 @@ int display_backlight(int val) { void display_init_seq(void) { display_unsleep(); } -void display_init(void) { +void display_init_all(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; /* Enable the LTDC and DMA2D Clock */ diff --git a/core/embed/trezorhal/stm32f4/displays/st7789v.c b/core/embed/trezorhal/stm32f4/displays/st7789v.c index 35a68129148..9d9bce4ed95 100644 --- a/core/embed/trezorhal/stm32f4/displays/st7789v.c +++ b/core/embed/trezorhal/stm32f4/displays/st7789v.c @@ -26,7 +26,6 @@ #include "irq.h" #include "memzero.h" #include "st7789v.h" -#include "supervise.h" #include STM32_HAL_H #ifdef TREZOR_MODEL_T @@ -253,6 +252,12 @@ int display_orientation(int degrees) { int display_get_orientation(void) { return DISPLAY_ORIENTATION; } +static inline uint32_t is_mode_handler(void) { + uint32_t r0; + __asm__ volatile("mrs %0, ipsr" : "=r"(r0)); + return (r0 & 0x1FF) != 0; +} + int display_backlight(int val) { #ifdef FRAMEBUFFER #ifndef BOARDLOADER @@ -384,12 +389,12 @@ void display_setup_te_interrupt(void) { HAL_EXTI_SetConfigLine(&EXTI_Handle, &EXTI_Config); // setup interrupt for tearing effect pin - HAL_NVIC_SetPriority(DISPLAY_TE_INTERRUPT_NUM, IRQ_PRI_DMA, 0); + NVIC_SetPriority(DISPLAY_TE_INTERRUPT_NUM, IRQ_PRI_NORMAL); #endif } #endif -void display_init(void) { +void display_init_all(void) { // init peripherals __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); @@ -564,7 +569,7 @@ void display_sync(void) {} #ifndef BOARDLOADER void DISPLAY_TE_INTERRUPT_HANDLER(void) { - HAL_NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); + NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); if (act_frame_buffer == 1) { bg_copy_start_const_out_8((uint8_t *)PhysFrameBuffer1, @@ -624,14 +629,14 @@ static void switch_fb_in_backround(void) { pending_fb_switch = true; __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); - svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM); + NVIC_EnableIRQ(DISPLAY_TE_INTERRUPT_NUM); } else { act_frame_buffer = 0; memcpy(PhysFrameBuffer1, PhysFrameBuffer0, sizeof(PhysFrameBuffer1)); pending_fb_switch = true; __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); - svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM); + NVIC_EnableIRQ(DISPLAY_TE_INTERRUPT_NUM); } } #endif @@ -723,6 +728,7 @@ void display_finish_actions(void) { #ifndef BOARDLOADER bg_copy_wait(); #endif + backlight_pwm_deinit(BACKLIGHT_RETAIN); } #else // NOT FRAMEBUFFER @@ -755,6 +761,11 @@ uint16_t display_get_window_offset(void) { return 0; } void display_shift_window(uint16_t pixels) {} -void display_finish_actions(void) {} +void display_finish_actions(void) { + backlight_pwm_deinit(BACKLIGHT_RETAIN); +#ifdef TREZOR_MODEL_T + display_set_big_endian(); +#endif +} #endif diff --git a/core/embed/trezorhal/stm32f4/displays/ug-2828tswig01.c b/core/embed/trezorhal/stm32f4/displays/ug-2828tswig01.c index 4e09309a6fb..54c602e8000 100644 --- a/core/embed/trezorhal/stm32f4/displays/ug-2828tswig01.c +++ b/core/embed/trezorhal/stm32f4/displays/ug-2828tswig01.c @@ -270,7 +270,7 @@ void display_init_seq(void) { display_unsleep(); } -void display_init(void) { +void display_init_all(void) { // init peripherals __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); diff --git a/core/embed/trezorhal/stm32f4/displays/vg-2864ksweg01.c b/core/embed/trezorhal/stm32f4/displays/vg-2864ksweg01.c index e841854e76f..a7166a070f5 100644 --- a/core/embed/trezorhal/stm32f4/displays/vg-2864ksweg01.c +++ b/core/embed/trezorhal/stm32f4/displays/vg-2864ksweg01.c @@ -153,7 +153,7 @@ void display_handle_init(void) { spi_handle.Init.Mode = SPI_MODE_MASTER; } -void display_init(void) { +void display_init_all(void) { OLED_DC_CLK_ENA(); OLED_CS_CLK_ENA(); OLED_RST_CLK_ENA(); diff --git a/core/embed/trezorhal/stm32f4/entropy.c b/core/embed/trezorhal/stm32f4/entropy.c new file mode 100644 index 00000000000..99fb0d69746 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/entropy.c @@ -0,0 +1,66 @@ +/* + * 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 "entropy.h" + +#include "entropy.h" +#include "flash_otp.h" +#include "model.h" +#include "mpu.h" +#include "rand.h" + +#include "stm32f4xx_ll_utils.h" + +#ifdef KERNEL_MODE + +static uint8_t g_hw_entropy[HW_ENTROPY_LEN]; + +void entropy_init(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + + // collect entropy from UUID + uint32_t w = LL_GetUID_Word0(); + memcpy(g_hw_entropy, &w, 4); + w = LL_GetUID_Word1(); + memcpy(g_hw_entropy + 4, &w, 4); + w = LL_GetUID_Word2(); + memcpy(g_hw_entropy + 8, &w, 4); + + mpu_restore(mpu_mode); + + // 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, g_hw_entropy + 12, + FLASH_OTP_BLOCK_SIZE), + NULL); +} + +void entropy_get(uint8_t *buf) { memcpy(buf, g_hw_entropy, HW_ENTROPY_LEN); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/fault_handlers.c b/core/embed/trezorhal/stm32f4/fault_handlers.c deleted file mode 100644 index f36e286baff..00000000000 --- a/core/embed/trezorhal/stm32f4/fault_handlers.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "common.h" - -void fault_handlers_init(void) { - // Enable BUS fault and USAGE fault handlers - SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk); -} - -void HardFault_Handler(void) { error_shutdown("(HF)"); } - -void MemManage_Handler_MM(void) { error_shutdown("(MM)"); } - -void MemManage_Handler_SO(void) { error_shutdown("(SO)"); } - -void BusFault_Handler(void) { error_shutdown("(BF)"); } - -void UsageFault_Handler(void) { error_shutdown("(UF)"); } - -void NMI_Handler(void) { - // Clock Security System triggered NMI - if ((RCC->CIR & RCC_CIR_CSSF) != 0) { - error_shutdown("(CS)"); - } -} diff --git a/core/embed/trezorhal/stm32f4/flash.c b/core/embed/trezorhal/stm32f4/flash.c index 8a34cc6947f..5a0b2c5cb4d 100644 --- a/core/embed/trezorhal/stm32f4/flash.c +++ b/core/embed/trezorhal/stm32f4/flash.c @@ -24,6 +24,8 @@ #include "common.h" #include "flash.h" +#ifdef KERNEL_MODE + #if defined STM32F427xx || defined STM32F429xx #define FLASH_SECTOR_COUNT 24 #elif defined STM32F405x @@ -198,3 +200,5 @@ secbool flash_write_block(uint16_t sector, uint32_t offset, const flash_block_t block) { return flash_write_word(sector, offset, block[0]); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/flash_otp.c b/core/embed/trezorhal/stm32f4/flash_otp.c index 28fbb34ffbf..6260426994e 100644 --- a/core/embed/trezorhal/stm32f4/flash_otp.c +++ b/core/embed/trezorhal/stm32f4/flash_otp.c @@ -22,6 +22,9 @@ #include "flash_otp.h" #include "common.h" #include "flash.h" +#include "mpu.h" + +#ifdef KERNEL_MODE #define FLASH_OTP_LOCK_BASE 0x1FFF7A00U @@ -35,10 +38,16 @@ secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, offset + datalen > FLASH_OTP_BLOCK_SIZE) { return secfalse; } + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + for (uint8_t i = 0; i < datalen; i++) { data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i); } + + mpu_restore(mpu_mode); + return sectrue; } @@ -48,6 +57,9 @@ secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, offset + datalen > FLASH_OTP_BLOCK_SIZE) { return secfalse; } + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + ensure(flash_unlock_write(), NULL); for (uint8_t i = 0; i < datalen; i++) { uint32_t address = @@ -57,6 +69,9 @@ secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, NULL); } ensure(flash_lock_write(), NULL); + + mpu_restore(mpu_mode); + return sectrue; } @@ -64,13 +79,30 @@ secbool flash_otp_lock(uint8_t block) { if (block >= FLASH_OTP_NUM_BLOCKS) { return secfalse; } + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + ensure(flash_unlock_write(), NULL); HAL_StatusTypeDef ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, FLASH_OTP_LOCK_BASE + block, 0x00); ensure(flash_lock_write(), NULL); + + mpu_restore(mpu_mode); + return sectrue * (ret == HAL_OK); } secbool flash_otp_is_locked(uint8_t block) { - return sectrue * (0x00 == *(__IO uint8_t *)(FLASH_OTP_LOCK_BASE + block)); + secbool is_locked; + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + + is_locked = + sectrue * (0x00 == *(__IO uint8_t *)(FLASH_OTP_LOCK_BASE + block)); + + mpu_restore(mpu_mode); + + return is_locked; } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/fwutils.c b/core/embed/trezorhal/stm32f4/fwutils.c new file mode 100644 index 00000000000..e0d4ad36946 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/fwutils.c @@ -0,0 +1,116 @@ +/* + * 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 "blake2s.h" +#include "error_handling.h" +#include "flash.h" +#include "flash_area.h" +#include "fwutils.h" +#include "image.h" +#include "model.h" + +#ifdef KERNEL_MODE + +#define FW_HASHING_CHUNK_SIZE 1024 + +secbool firmware_calc_hash(const uint8_t* challenge, size_t challenge_len, + uint8_t* hash, size_t hash_len, + firmware_hash_callback_t callback, + void* callback_context) { + BLAKE2S_CTX ctx; + + if (challenge_len != 0) { + if (blake2s_InitKey(&ctx, BLAKE2S_DIGEST_LENGTH, challenge, + challenge_len) != 0) { + return secfalse; + } + } else { + blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); + } + + uint32_t firmware_size = flash_area_get_size(&FIRMWARE_AREA); + uint32_t chunks = firmware_size / FW_HASHING_CHUNK_SIZE; + + ensure((firmware_size % FW_HASHING_CHUNK_SIZE == 0) * sectrue, + "Cannot compute FW hash."); + + for (int i = 0; i < chunks; i++) { + if (callback != NULL && (i % 128 == 0)) { + callback(callback_context, i, chunks); + } + + const void* data = flash_area_get_address( + &FIRMWARE_AREA, i * FW_HASHING_CHUNK_SIZE, FW_HASHING_CHUNK_SIZE); + + if (data == NULL) { + return secfalse; + } + + blake2s_Update(&ctx, data, FW_HASHING_CHUNK_SIZE); + } + + if (callback != NULL) { + callback(callback_context, chunks, chunks); + } + + if (blake2s_Final(&ctx, hash, hash_len) != 0) { + return secfalse; + } + + return sectrue; +} + +secbool firmware_get_vendor(char* buff, size_t buff_size) { + const void* data = flash_area_get_address(&FIRMWARE_AREA, 0, 0); + + vendor_header vhdr = {0}; + + if (data == NULL || sectrue != read_vendor_header(data, &vhdr)) { + return secfalse; + } + + if (buff == NULL || buff_size < vhdr.vstr_len + 1) { + return secfalse; + } + + strncpy(buff, vhdr.vstr, buff_size); + + return sectrue; +} + +void firmware_invalidate_header(void) { +#ifdef STM32U5 + // on stm32u5, we need to disable the instruction cache before erasing the + // firmware - otherwise, the write check will fail + ICACHE->CR &= ~ICACHE_CR_EN; +#endif + + // erase start of the firmware (metadata) -> invalidate FW + ensure(flash_unlock_write(), NULL); + for (int i = 0; i < (1024 / FLASH_BLOCK_SIZE); i++) { + flash_block_t data = {0}; + ensure(flash_area_write_block(&FIRMWARE_AREA, i * FLASH_BLOCK_SIZE, data), + NULL); + } + ensure(flash_lock_write(), NULL); +} + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/i2c.c b/core/embed/trezorhal/stm32f4/i2c.c deleted file mode 100644 index 319342b7657..00000000000 --- a/core/embed/trezorhal/stm32f4/i2c.c +++ /dev/null @@ -1,199 +0,0 @@ - - -#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; - uint32_t Reset; -} i2c_instance_t; - -i2c_instance_t i2c_defs[I2C_COUNT] = { - { - .Instance = I2C_INSTANCE_0, - .SclPort = I2C_INSTANCE_0_SCL_PORT, - .SdaPort = I2C_INSTANCE_0_SDA_PORT, - .SclPin = I2C_INSTANCE_0_SCL_PIN, - .SdaPin = I2C_INSTANCE_0_SDA_PIN, - .PinAF = I2C_INSTANCE_0_PIN_AF, - .Reset = I2C_INSTANCE_0_RESET_FLG, - }, -#ifdef I2C_INSTANCE_1 - { - .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, - .Reset = I2C_INSTANCE_1_RESET_FLG, - }, -#endif - -}; - -void i2c_init_instance(uint16_t idx, i2c_instance_t *instance) { - if (i2c_handle[idx].Instance) { - return; - } - - GPIO_InitTypeDef GPIO_InitStructure = {0}; - - // 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.ClockSpeed = 200000; - i2c_handle[idx].Init.DutyCycle = I2C_DUTYCYCLE_16_9; - 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])) { - error_shutdown("I2C was not loaded properly."); - return; - } -} - -void i2c_init(void) { - // enable I2C clock - I2C_INSTANCE_0_CLK_EN(); - I2C_INSTANCE_0_SCL_CLK_EN(); - I2C_INSTANCE_0_SDA_CLK_EN(); - - i2c_init_instance(0, &i2c_defs[0]); - -#ifdef I2C_INSTANCE_1 - I2C_INSTANCE_1_CLK_EN(); - I2C_INSTANCE_1_SCL_CLK_EN(); - I2C_INSTANCE_1_SDA_CLK_EN(); - i2c_init_instance(1, &i2c_defs[1]); -#endif -} - -void i2c_deinit(uint16_t idx) { - 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) - ; -} - -// I2C cycle described in section 2.9.7 of STM CD00288116 Errata sheet -// -// https://www.st.com/content/ccc/resource/technical/document/errata_sheet/7f/05/b0/bc/34/2f/4c/21/CD00288116.pdf/files/CD00288116.pdf/jcr:content/translations/en.CD00288116.pdf - -void i2c_cycle(uint16_t idx) { - i2c_instance_t *instance = &i2c_defs[0]; - - // 1. Disable I2C peripheral - i2c_deinit(idx); - - // 2. Configure SCL/SDA as GPIO OUTPUT Open Drain - GPIO_InitTypeDef GPIO_InitStructure = {0}; - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStructure.Pin = instance->SdaPin; - HAL_GPIO_Init(instance->SdaPort, &GPIO_InitStructure); - GPIO_InitStructure.Pin = instance->SclPin; - HAL_GPIO_Init(instance->SclPort, &GPIO_InitStructure); - HAL_Delay(50); - - // 3. Check SCL and SDA High level - i2c_ensure_pin(instance->SclPort, instance->SclPin, GPIO_PIN_SET); - i2c_ensure_pin(instance->SdaPort, instance->SdaPin, GPIO_PIN_SET); - // 4+5. Check SDA Low level - i2c_ensure_pin(instance->SdaPort, instance->SdaPin, GPIO_PIN_RESET); - // 6+7. Check SCL Low level - i2c_ensure_pin(instance->SclPort, instance->SclPin, GPIO_PIN_RESET); - // 8+9. Check SCL High level - i2c_ensure_pin(instance->SclPort, instance->SclPin, GPIO_PIN_SET); - // 10+11. Check SDA High level - i2c_ensure_pin(instance->SclPort, instance->SdaPin, GPIO_PIN_SET); - - // 12. Configure SCL/SDA as Alternate function Open-Drain - GPIO_InitStructure.Mode = GPIO_MODE_AF_OD; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStructure.Alternate = instance->PinAF; - GPIO_InitStructure.Pin = instance->SclPin; - HAL_GPIO_Init(instance->SclPort, &GPIO_InitStructure); - GPIO_InitStructure.Pin = instance->SdaPin; - HAL_GPIO_Init(instance->SdaPort, &GPIO_InitStructure); - HAL_Delay(50); - - // 13. Force reset - RCC->APB1RSTR |= instance->Reset; - - HAL_Delay(50); - - // 14. Release reset - RCC->APB1RSTR &= ~instance->Reset; - - // 15. Enable the I2C peripheral - i2c_init_instance(idx, instance); - HAL_Delay(10); -} - -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/stm32f4/i2c.h b/core/embed/trezorhal/stm32f4/i2c.h deleted file mode 100644 index cb0eec852ee..00000000000 --- a/core/embed/trezorhal/stm32f4/i2c.h +++ /dev/null @@ -1,15 +0,0 @@ - -#include STM32_HAL_H - -void i2c_init(void); -void i2c_cycle(uint16_t idx); -HAL_StatusTypeDef i2c_transmit(uint16_t idx, uint8_t addr, uint8_t *data, - uint16_t len, uint32_t timeout); -HAL_StatusTypeDef i2c_receive(uint16_t idx, uint8_t addr, uint8_t *data, - uint16_t len, uint32_t timeout); -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); -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); diff --git a/core/embed/trezorhal/stm32f4/i2c_bus.c b/core/embed/trezorhal/stm32f4/i2c_bus.c new file mode 100644 index 00000000000..5b4c11e52c1 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/i2c_bus.c @@ -0,0 +1,953 @@ +/* + * 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 TREZOR_BOARD + +#include + +#include "common.h" +#include "i2c_bus.h" +#include "irq.h" +#include "mpu.h" +#include "systimer.h" + +#ifdef KERNEL_MODE + +// I2C bus SCL clock frequency +#define I2C_BUS_SCL_FREQ 200000 // Hz + +// We expect the I2C bus to be running at ~200kHz +// and max response time of the device is 1000us +#define I2C_BUS_CHAR_TIMEOUT (50 + 5) // us +#define I2C_BUS_OP_TIMEOUT 1000 // us + +#define I2C_BUS_TIMEOUT(n) \ + ((I2C_BUS_CHAR_TIMEOUT * (1 + n) + I2C_BUS_OP_TIMEOUT + 999) / 1000) + +// I2C bus hardware definition +typedef struct { + // I2C controller registers + I2C_TypeDef* regs; + // SCL pin GPIO port + GPIO_TypeDef* scl_port; + // SDA pin GPIO port + GPIO_TypeDef* sda_port; + // SCL pin number + uint16_t scl_pin; + // SDA pin number + uint16_t sda_pin; + // Alternate function for SCL and SDA pins + uint8_t pin_af; + // Register for I2C controller reset + volatile uint32_t* reset_reg; + // Reset bit specific for this I2C controller + uint32_t reset_bit; + // I2C event IRQ number + uint32_t ev_irq; + // I2C error IRQ number + uint32_t er_irq; + // Guard time [us] between STOP and START condition. + // If zero, the guard time is not used. + uint16_t guard_time; +} i2c_bus_def_t; + +// I2C bus hardware definitions +static const i2c_bus_def_t g_i2c_bus_def[I2C_COUNT] = { + { + .regs = I2C_INSTANCE_0, + .scl_port = I2C_INSTANCE_0_SCL_PORT, + .sda_port = I2C_INSTANCE_0_SDA_PORT, + .scl_pin = I2C_INSTANCE_0_SCL_PIN, + .sda_pin = I2C_INSTANCE_0_SDA_PIN, + .pin_af = I2C_INSTANCE_0_PIN_AF, + .reset_reg = I2C_INSTANCE_0_RESET_REG, + .reset_bit = I2C_INSTANCE_0_RESET_BIT, + .ev_irq = I2C_INSTANCE_0_EV_IRQn, + .er_irq = I2C_INSTANCE_0_ER_IRQn, + .guard_time = I2C_INSTANCE_0_GUARD_TIME, + }, +#ifdef I2C_INSTANCE_1 + { + .regs = I2C_INSTANCE_1, + .scl_port = I2C_INSTANCE_1_SCL_PORT, + .sda_port = I2C_INSTANCE_1_SDA_PORT, + .scl_pin = I2C_INSTANCE_1_SCL_PIN, + .sda_pin = I2C_INSTANCE_1_SDA_PIN, + .pin_af = I2C_INSTANCE_1_PIN_AF, + .reset_reg = I2C_INSTANCE_1_RESET_REG, + .reset_bit = I2C_INSTANCE_1_RESET_BIT, + .ev_irq = I2C_INSTANCE_1_EV_IRQn, + .er_irq = I2C_INSTANCE_1_ER_IRQn, + .guard_time = I2C_INSTANCE_1_GUARD_TIME, + }, +#endif +#ifdef I2C_INSTANCE_2 + { + .regs = I2C_INSTANCE_2, + .scl_port = I2C_INSTANCE_2_SCL_PORT, + .sda_port = I2C_INSTANCE_2_SDA_PORT, + .scl_pin = I2C_INSTANCE_2_SCL_PIN, + .sda_pin = I2C_INSTANCE_2_SDA_PIN, + .pin_af = I2C_INSTANCE_2_PIN_AF, + .reset_reg = I2C_INSTANCE_2_RESET_REG, + .reset_bit = I2C_INSTANCE_2_RESET_BIT, + .ev_irq = I2C_INSTANCE_2_EV_IRQn, + .er_irq = I2C_INSTANCE_2_ER_IRQn, + .guard_time = I2C_INSTANCE_2_GUARD_TIME, + }, +#endif +}; + +struct i2c_bus { + // Number of references to the bus + // (0 means the bus is not initialized) + uint32_t refcount; + + // Hardware definition + const i2c_bus_def_t* def; + + // Timer for timeout handling + systimer_t* timer; + + // Head of the packet queue + // (this packet is currently being processed) + i2c_packet_t* queue_head; + // Tail of the packet queue + // (this packet is the last in the queue) + i2c_packet_t* queue_tail; + + // Next operation index in the current packet + // == 0 => no operation is being processed + // == queue_head->op_count => no more operations + int next_op; + + // Current operation address byte + uint8_t addr_byte; + // Points to the data buffer of the current operation + uint8_t* buff_ptr; + // Remaining number of bytes of the buffer to transfer + uint16_t buff_size; + // Remaining number of bytes of the current operation + // (if the transfer is split into multiple operations it + // may be different from buff_size) + uint16_t transfer_size; + // For case of split transfer, points to the next operation + // that is part of the current transfer + int transfer_op; + + // Set if the STOP condition is requested after the current operation + // when data transfer is completed. + bool stop_requested; + // Set if pending transaction is being aborted + bool abort_pending; + + // Flag indicating that the completion callback is being executed + bool callback_executed; + + // The last time [us] the STOP condition was issued + uint64_t stop_time; +}; + +// I2C bus driver instances +static i2c_bus_t g_i2c_bus_driver[I2C_COUNT] = {0}; + +// Check if the I2C bus pointer is valid +static inline bool i2c_bus_ptr_valid(const i2c_bus_t* bus) { + if (bus >= &g_i2c_bus_driver[0] && bus < &g_i2c_bus_driver[I2C_COUNT]) { + uintptr_t offset = (uintptr_t)bus - (uintptr_t)&g_i2c_bus_driver[0]; + if (offset % sizeof(i2c_bus_t) == 0) { + return bus->refcount > 0; + } + } + return false; +} + +// forward declarations +static void i2c_bus_timer_callback(void* context); +static void i2c_bus_head_continue(i2c_bus_t* bus); + +static void i2c_bus_unlock(i2c_bus_t* bus) { + const i2c_bus_def_t* def = bus->def; + + GPIO_InitTypeDef GPIO_InitStructure = {0}; + + // Set SDA and SCL high + HAL_GPIO_WritePin(def->sda_port, def->sda_pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(def->scl_port, def->scl_pin, GPIO_PIN_SET); + + // Configure SDA and SCL as open-drain output + // and connect to the I2C peripheral + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + + GPIO_InitStructure.Pin = def->scl_pin; + HAL_GPIO_Init(def->scl_port, &GPIO_InitStructure); + + GPIO_InitStructure.Pin = def->sda_pin; + HAL_GPIO_Init(def->sda_port, &GPIO_InitStructure); + + uint32_t clock_count = 16; + + while ((HAL_GPIO_ReadPin(def->sda_port, def->sda_pin) == GPIO_PIN_RESET) && + (clock_count-- > 0)) { + // Clock SCL + HAL_GPIO_WritePin(def->scl_port, def->scl_pin, GPIO_PIN_RESET); + systick_delay_us(10); + HAL_GPIO_WritePin(def->scl_port, def->scl_pin, GPIO_PIN_SET); + systick_delay_us(10); + } +} + +static void i2c_bus_reset(i2c_bus_t* bus) { + const i2c_bus_def_t* def = bus->def; + + // Reset I2C peripheral + *def->reset_reg |= def->reset_bit; + *def->reset_reg &= ~def->reset_bit; + + I2C_TypeDef* regs = def->regs; + + // Configure I2C peripheral + + uint32_t pclk_hz = HAL_RCC_GetPCLK1Freq(); + uint32_t pclk_mhz = I2C_FREQRANGE(pclk_hz); + uint32_t i2c_speed_hz = I2C_BUS_SCL_FREQ; + + regs->CR1 = 0; + regs->TRISE = I2C_RISE_TIME(pclk_mhz, i2c_speed_hz); + regs->CR2 = pclk_mhz; + regs->CCR = I2C_SPEED(pclk_hz, i2c_speed_hz, I2C_DUTYCYCLE_16_9); + regs->FLTR = 0; + regs->OAR1 = 0; + regs->OAR2 = 0; + regs->CR1 |= I2C_CR1_PE; +} + +static void i2c_bus_deinit(i2c_bus_t* bus) { + const i2c_bus_def_t* def = bus->def; + + systimer_delete(bus->timer); + + if (bus->def == NULL) { + return; + } + + NVIC_DisableIRQ(def->ev_irq); + NVIC_DisableIRQ(def->er_irq); + + I2C_TypeDef* regs = def->regs; + + // Disable I2C peripheral + regs->CR1 = 0; + + // Reset I2C peripheral + *def->reset_reg |= def->reset_bit; + *def->reset_reg &= ~def->reset_bit; + + bus->def = NULL; +} + +static bool i2c_bus_init(i2c_bus_t* bus, int bus_index) { + memset(bus, 0, sizeof(i2c_bus_t)); + + switch (bus_index) { + case 0: + // enable I2C clock + I2C_INSTANCE_0_CLK_EN(); + I2C_INSTANCE_0_SCL_CLK_EN(); + I2C_INSTANCE_0_SDA_CLK_EN(); + break; + +#ifdef I2C_INSTANCE_1 + case 1: + I2C_INSTANCE_1_CLK_EN(); + I2C_INSTANCE_1_SCL_CLK_EN(); + I2C_INSTANCE_1_SDA_CLK_EN(); + break; +#endif + +#ifdef I2C_INSTANCE_2 + case 2: + I2C_INSTANCE_2_CLK_EN(); + I2C_INSTANCE_2_SCL_CLK_EN(); + I2C_INSTANCE_2_SDA_CLK_EN(); + break; +#endif + default: + goto cleanup; + } + + const i2c_bus_def_t* def = &g_i2c_bus_def[bus_index]; + + bus->def = def; + + // Unlocks potentially locked I2C bus by + // generating several clock pulses on SCL while SDA is low + i2c_bus_unlock(bus); + + GPIO_InitTypeDef GPIO_InitStructure = {0}; + + // Configure SDA and SCL as open-drain output + // and connect to the I2C peripheral + GPIO_InitStructure.Mode = GPIO_MODE_AF_OD; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + + GPIO_InitStructure.Alternate = def->pin_af; + GPIO_InitStructure.Pin = def->scl_pin; + HAL_GPIO_Init(def->scl_port, &GPIO_InitStructure); + + GPIO_InitStructure.Alternate = def->pin_af; + GPIO_InitStructure.Pin = def->sda_pin; + HAL_GPIO_Init(def->sda_port, &GPIO_InitStructure); + + i2c_bus_reset(bus); + + NVIC_SetPriority(def->ev_irq, IRQ_PRI_NORMAL); + NVIC_SetPriority(def->er_irq, IRQ_PRI_NORMAL); + + NVIC_EnableIRQ(def->ev_irq); + NVIC_EnableIRQ(def->er_irq); + + bus->timer = systimer_create(i2c_bus_timer_callback, bus); + if (bus->timer == NULL) { + goto cleanup; + } + + return true; + +cleanup: + i2c_bus_deinit(bus); + return false; +} + +i2c_bus_t* i2c_bus_open(uint8_t bus_index) { + if (bus_index >= I2C_COUNT) { + return NULL; + } + + i2c_bus_t* bus = &g_i2c_bus_driver[bus_index]; + + if (bus->refcount == 0) { + if (!i2c_bus_init(bus, bus_index)) { + return NULL; + } + } + + ++bus->refcount; + + return bus; +} + +void i2c_bus_close(i2c_bus_t* bus) { + if (!i2c_bus_ptr_valid(bus)) { + return; + } + + if (bus->refcount > 0) { + if (--bus->refcount == 0) { + i2c_bus_deinit(bus); + } + } +} + +i2c_status_t i2c_packet_status(const i2c_packet_t* packet) { + irq_key_t irq_key = irq_lock(); + i2c_status_t status = packet->status; + irq_unlock(irq_key); + return status; +} + +i2c_status_t i2c_packet_wait(const i2c_packet_t* packet) { + while (true) { + i2c_status_t status = i2c_packet_status(packet); + + if (status != I2C_STATUS_PENDING) { + return status; + } + + // Enter sleep mode and wait for any interrupt + __WFI(); + } +} + +// Invokes the packet completion callback +static inline void i2c_bus_invoke_callback(i2c_bus_t* bus, i2c_packet_t* packet, + i2c_status_t status) { + packet->status = status; + if (packet->callback) { + bus->callback_executed = true; + packet->callback(packet->context, packet); + bus->callback_executed = false; + } +} + +// Appends the packet to the end of the queue +// Returns true if the queue was empty before +// Expects disabled IRQ or calling from IRQ context +static inline bool i2c_bus_add_packet(i2c_bus_t* bus, i2c_packet_t* packet) { + if (bus->queue_tail == NULL) { + bus->queue_head = packet; + bus->queue_tail = packet; + return true; + } else { + bus->queue_tail->next = packet; + bus->queue_tail = packet; + return false; + } +} + +// Removes the packet from the queue (if present) +// Returns true if the removed we removed head of the queue +// Expects disabled IRQ or calling from IRQ context +static inline bool i2c_bus_remove_packet(i2c_bus_t* bus, i2c_packet_t* packet) { + if (packet == bus->queue_head) { + // Remove head of the queue + bus->queue_head = packet->next; + // If the removed packet was also the tail, reset the tail + if (bus->queue_tail == packet) { + bus->queue_tail = NULL; + } + packet->next = NULL; + return true; + } + + // Remove from the middle or tail of the queue + i2c_packet_t* p = bus->queue_head; + while (p->next != NULL && p->next != packet) { + p = p->next; + } + + if (p->next == packet) { + // The packet found in the queue, remove it + p->next = packet->next; + // Update the tail if necessary + if (bus->queue_tail == packet) { + bus->queue_tail = p; + } + packet->next = NULL; + } + + return false; +} + +i2c_status_t i2c_bus_submit(i2c_bus_t* bus, i2c_packet_t* packet) { + if (!i2c_bus_ptr_valid(bus) || packet == NULL) { + // Invalid bus or packet + return I2C_STATUS_ERROR; + } + + if (packet->next != NULL) { + // Packet is already queued + return I2C_STATUS_ERROR; + } + + packet->status = I2C_STATUS_PENDING; + + // Insert packet into the queue + irq_key_t irq_key = irq_lock(); + if (i2c_bus_add_packet(bus, packet)) { + // The queue was empty, start the operation + if (!bus->callback_executed && !bus->abort_pending) { + i2c_bus_head_continue(bus); + } + } + irq_unlock(irq_key); + + return I2C_STATUS_OK; +} + +void i2c_bus_abort(i2c_bus_t* bus, i2c_packet_t* packet) { + if (!i2c_bus_ptr_valid(bus) || packet == NULL) { + // Invalid bus or packet + return; + } + + irq_key_t irq_key = irq_lock(); + + if (packet->status == I2C_STATUS_PENDING) { + if (i2c_bus_remove_packet(bus, packet) && bus->next_op > 0) { + // The packet was being processed + + // Reset internal state + bus->next_op = 0; + bus->buff_ptr = NULL; + bus->buff_size = 0; + bus->transfer_size = 0; + bus->transfer_op = 0; + + // Inform interrupt handler about pending abort + bus->abort_pending = true; + bus->stop_requested = true; + + // Abort operation may fail if the bus is busy or noisy + // so we need to set a timeout. + systimer_set(bus->timer, I2C_BUS_TIMEOUT(2)); + } + packet->status = I2C_STATUS_ABORTED; + } + + irq_unlock(irq_key); +} + +// Completes the current packet by removing it from the queue +// an invoking the completion callback +// +// Must be called with IRQ disabled or from IRQ context +// Expects the operation is finished +static void i2c_bus_head_complete(i2c_bus_t* bus, i2c_status_t status) { + i2c_packet_t* packet = bus->queue_head; + if (packet != NULL) { + // Remove packet from the queue + i2c_bus_remove_packet(bus, packet); + + // Reset internal state + bus->next_op = 0; + bus->buff_ptr = NULL; + bus->buff_size = 0; + bus->transfer_size = 0; + bus->transfer_op = 0; + bus->abort_pending = false; + + systimer_unset(bus->timer); + + // Invoke the completion callback + i2c_bus_invoke_callback(bus, packet, status); + } +} + +// Starts the next operation in the packet by +// programming the I2C controller +// +// Must be called with IRQ disabled or from IRQ context +// Expects no other operation is being processed +static void i2c_bus_head_continue(i2c_bus_t* bus) { + I2C_TypeDef* regs = bus->def->regs; + + if (bus->stop_requested) { + // Issue STOP condition + regs->CR1 |= I2C_CR1_STOP; + if (bus->def->guard_time > 0) { + bus->stop_time = systick_us(); + } + bus->stop_requested = false; + } + + if (bus->abort_pending) { + systimer_unset(bus->timer); + bus->abort_pending = false; + } + + // Check if the bus is in a faulty state + if (bus->queue_head != NULL && bus->next_op == 0) { + uint32_t sr2 = regs->SR2; + + if ((sr2 & I2C_SR2_BUSY) && ((sr2 & I2C_SR2_MSL) == 0)) { + // the bus is busy but not in master mode. + // It may happen if in case of noise or other issues. + i2c_bus_reset(bus); + } + } + + uint32_t cr1 = regs->CR1; + cr1 &= ~(I2C_CR1_POS | I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_START); + + uint32_t cr2 = regs->CR2; + cr2 &= ~(I2C_CR2_ITBUFEN | I2C_CR2_ITEVTEN | I2C_CR2_ITERREN); + + if (bus->queue_head != NULL) { + i2c_packet_t* packet = bus->queue_head; + + if (bus->next_op < packet->op_count) { + i2c_op_t* op = &packet->ops[bus->next_op++]; + + // Get data ptr and data length + if (op->flags & I2C_FLAG_EMBED) { + bus->buff_ptr = op->data; + bus->buff_size = MIN(op->size, sizeof(op->data)); + } else { + bus->buff_ptr = op->ptr; + bus->buff_size = op->size; + } + + // Calculate transfer size + bus->transfer_size = bus->buff_size; + bus->transfer_op = bus->next_op; + + // Include following operations in the transfer if: + // 1) We are not processing the last operation + // 2) STOP condition is not requested in the current operation + // 3) START condition is not requested in the next operation + // 4) The next operation has the same direction + + while ((bus->next_op != packet->op_count) && + ((op->flags & I2C_FLAG_STOP) == 0) && + (((op + 1)->flags & I2C_FLAG_START) == 0) && + (((op + 1)->flags & I2C_FLAG_TX) == (op->flags & I2C_FLAG_TX))) { + // Move to the next operation + op = &packet->ops[bus->next_op++]; + + if (op->flags & I2C_FLAG_EMBED) { + bus->transfer_size += MIN(op->size, sizeof(op->data)); + } else { + bus->transfer_size += op->size; + } + } + + // STOP condition: + // 1) if it is explicitly requested + // 2) if it is the last operation in the packet + bus->stop_requested = ((op->flags & I2C_FLAG_STOP) != 0) || + (bus->next_op == packet->op_count); + + // Calculate address byte + bus->addr_byte = packet->address << 1; + + // ACK, POS, ITBUFEN flags are set based on the operation + if (bus->transfer_size > 0) { + if (op->flags & I2C_FLAG_TX) { + cr2 |= I2C_CR2_ITBUFEN; + } else if (op->flags & I2C_FLAG_RX) { + bus->addr_byte |= 1; // Set RW bit to 1 (READ) + if (bus->transfer_size == 1) { + cr2 |= I2C_CR2_ITBUFEN; + } else if (bus->transfer_size == 2) { + cr1 |= I2C_CR1_POS; + } else if (bus->transfer_size == 3) { + cr1 |= I2C_CR1_ACK; + } else if (bus->transfer_size > 3) { + cr2 |= I2C_CR2_ITBUFEN; + cr1 |= I2C_CR1_ACK; + } + } + } + + // Enable event and error interrupts + cr2 |= I2C_CR2_ITEVTEN | I2C_CR2_ITERREN; + + // Generate start condition + // (this also clears all status flags) + cr1 |= I2C_CR1_START; + + // Each operation has its own timeout calculated + // based on the number of bytes to transfer and the bus speed + + // expected operation overhead + systimer_set(bus->timer, + I2C_BUS_TIMEOUT(bus->transfer_size) + packet->timeout); + + // Guard time between operations STOP and START condition + if (bus->def->guard_time > 0) { + // Add 5us as a safety margin since the stop_time was set before the + // STOP condition was issued + uint16_t guard_time = bus->def->guard_time + 5; + while (systick_us() - bus->stop_time < guard_time) + ; + } + } + + // Clear BTF flag + (void)regs->DR; + } + + regs->CR1 = cr1; + regs->CR2 = cr2; +} + +// Timer callback handling I2C bus timeout +static void i2c_bus_timer_callback(void* context) { + i2c_bus_t* bus = (i2c_bus_t*)context; + + if (bus->abort_pending) { + // This may be caused by the bus being busy/noisy. + // Reset I2C Controller + i2c_bus_reset(bus); + // Start the next packet + i2c_bus_head_continue(bus); + } else { + // Timeout during normal operation occurred + i2c_packet_t* packet = bus->queue_head; + if (packet != NULL) { + // Determine the status based on the current bus state + I2C_TypeDef* regs = bus->def->regs; + i2c_status_t status; + + if ((regs->CR1 & I2C_CR1_START) && (regs->SR2 & I2C_SR2_BUSY)) { + // START condition was issued but the bus is still busy + status = I2C_STATUS_BUSY; + } else { + status = I2C_STATUS_TIMEOUT; + } + + // Abort pending packet + i2c_bus_abort(bus, packet); + // Invoke the completion callback + i2c_bus_invoke_callback(bus, packet, status); + } + } +} + +static uint8_t i2c_bus_read_buff(i2c_bus_t* bus) { + if (bus->transfer_size > 0) { + while (bus->buff_size == 0 && bus->transfer_op < bus->next_op) { + i2c_op_t* op = &bus->queue_head->ops[bus->transfer_op++]; + if (op->flags & I2C_FLAG_EMBED) { + bus->buff_ptr = op->data; + bus->buff_size = MIN(op->size, sizeof(op->data)); + } else { + bus->buff_ptr = op->ptr; + bus->buff_size = op->size; + } + } + + --bus->transfer_size; + + if (bus->buff_size > 0) { + --bus->buff_size; + return *bus->buff_ptr++; + } + } + + return 0; +} + +static void i2c_bus_write_buff(i2c_bus_t* bus, uint8_t data) { + if (bus->transfer_size > 0) { + while (bus->buff_size == 0 && bus->transfer_op < bus->next_op) { + i2c_op_t* op = &bus->queue_head->ops[bus->transfer_op++]; + if (op->flags & I2C_FLAG_EMBED) { + bus->buff_ptr = op->data; + bus->buff_size = MIN(op->size, sizeof(op->data)); + } else { + bus->buff_ptr = op->ptr; + bus->buff_size = op->size; + } + } + + --bus->transfer_size; + + if (bus->buff_size > 0) { + *bus->buff_ptr++ = data; + --bus->buff_size; + } + } +} + +// I2C bus event interrupt handler +static void i2c_bus_ev_handler(i2c_bus_t* bus) { + I2C_TypeDef* regs = bus->def->regs; + + uint32_t sr1 = regs->SR1; + + if (sr1 & I2C_SR1_SB) { + // START condition generated + // Send the address byte + regs->DR = bus->addr_byte; + // Operation cannot be aborted at this point. + // We need to wait for ADDR flag. + } else if (sr1 & I2C_SR1_ADDR) { + // Address sent and ACKed by the slave + // By reading SR2 we clear ADDR flag and start the data transfer + regs->SR2; + + if (bus->abort_pending) { + // Only TX operation can be aborted at this point + // For RX operation, we need to wait for the first byte + if ((bus->addr_byte & 1) == 0) { + // Issue STOP condition and start the next packet + i2c_bus_head_continue(bus); + } + } else if (bus->transfer_size == 0) { + // Operation contains only address without any data + if (bus->next_op == bus->queue_head->op_count) { + i2c_bus_head_complete(bus, I2C_STATUS_OK); + } + i2c_bus_head_continue(bus); + } + } else if ((bus->addr_byte & 1) == 0) { + // Data transmit phase + if (bus->abort_pending) { + // Issue STOP condition and start the next packet + i2c_bus_head_continue(bus); + } else if ((sr1 & I2C_SR1_TXE) && (regs->CR2 & I2C_CR2_ITBUFEN)) { + // I2C controller transmit buffer is empty. + // The interrupt flag is cleared by writing the DR register. + if (bus->transfer_size > 0) { + // Send the next byte + regs->DR = i2c_bus_read_buff(bus); + if (bus->transfer_size == 0) { + // All data bytes were transmitted + // Disable RXNE interrupt and wait for BTF + regs->CR2 &= ~I2C_CR2_ITBUFEN; + } + } + } else if (sr1 & I2C_SR1_BTF) { + if (bus->transfer_size == 0) { + // All data bytes were shifted out + if (bus->next_op == bus->queue_head->op_count) { + // Last operation in the packet + i2c_bus_head_complete(bus, I2C_STATUS_OK); + } + i2c_bus_head_continue(bus); + } + } + } else { // Data receive phase + if (bus->abort_pending) { + regs->CR1 &= ~(I2C_CR1_ACK | I2C_CR1_POS); + (void)regs->DR; + // Issue STOP condition and start the next packet + i2c_bus_head_continue(bus); + } else if ((sr1 & I2C_SR1_RXNE) && (regs->CR2 & I2C_CR2_ITBUFEN)) { + uint8_t received_byte = regs->DR; + if (bus->transfer_size > 0) { + // Receive the next byte + i2c_bus_write_buff(bus, received_byte); + if (bus->transfer_size == 3) { + // 3 bytes left to receive + // Disable RXNE interrupt and wait for BTF + regs->CR2 &= ~I2C_CR2_ITBUFEN; + } else if (bus->transfer_size == 0) { + // All data bytes were received + // We get here only in case of 1 byte transfers + if (bus->next_op == bus->queue_head->op_count) { + // Last operation in the packet + i2c_bus_head_complete(bus, I2C_STATUS_OK); + } + i2c_bus_head_continue(bus); + } + } + } else if (sr1 & I2C_SR1_BTF) { + if (bus->transfer_size == 3) { + // 3 bytes left to receive + regs->CR1 &= ~I2C_CR1_ACK; + i2c_bus_write_buff(bus, regs->DR); + } else if (bus->transfer_size == 2) { + // 2 left bytes are already in DR a shift register + if (bus->stop_requested) { + // Issue STOP condition before reading the 2 last bytes + regs->CR1 |= I2C_CR1_STOP; + if (bus->def->guard_time > 0) { + bus->stop_time = systick_us(); + } + bus->stop_requested = false; + } + i2c_bus_write_buff(bus, regs->DR); + i2c_bus_write_buff(bus, regs->DR); + + if (bus->next_op == bus->queue_head->op_count) { + i2c_bus_head_complete(bus, I2C_STATUS_OK); + } + i2c_bus_head_continue(bus); + } + } + } +} + +// I2C bus error interrupt handler +static void i2c_bus_er_handler(i2c_bus_t* bus) { + I2C_TypeDef* regs = bus->def->regs; + + uint32_t sr1 = regs->SR1; + + // Clear error flags + regs->SR1 &= ~(I2C_SR1_AF | I2C_SR1_ARLO | I2C_SR1_BERR); + + if (sr1 & I2C_SR1_AF) { + // NACK received + if (bus->abort_pending) { + // Start the next packet + i2c_bus_head_continue(bus); + } else if (bus->next_op > 0) { + // Complete packet with error + i2c_bus_head_complete(bus, I2C_STATUS_NACK); + // Issue stop condition and start the next packet + bus->stop_requested = true; + i2c_bus_head_continue(bus); + } else { + // Invalid state + } + } + + if (sr1 & I2C_SR1_ARLO) { + if (bus->abort_pending) { + // Packet aborted or invalid state + // Start the next packet + bus->stop_requested = false; + i2c_bus_head_continue(bus); + } else if (bus->next_op > 0) { + // Arbitration lost, complete packet with error + i2c_bus_head_complete(bus, I2C_STATUS_ERROR); + // Start the next packet + bus->stop_requested = false; + i2c_bus_head_continue(bus); + } + } + + if (sr1 & I2C_SR1_BERR) { + // Bus error + // Ignore and continue with pending operation + } +} + +// Interrupt handlers + +#ifdef I2C_INSTANCE_0 +void I2C_INSTANCE_0_EV_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_ev_handler(&g_i2c_bus_driver[0]); + mpu_restore(mpu_mode); +} + +void I2C_INSTANCE_0_ER_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_er_handler(&g_i2c_bus_driver[0]); + mpu_restore(mpu_mode); +} +#endif + +#ifdef I2C_INSTANCE_1 +void I2C_INSTANCE_1_EV_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_ev_handler(&g_i2c_bus_driver[1]); + mpu_restore(mpu_mode); +} + +void I2C_INSTANCE_1_ER_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_er_handler(&g_i2c_bus_driver[1]); + mpu_restore(mpu_mode); +} +#endif + +#ifdef I2C_INSTANCE_2 +void I2C_INSTANCE_2_EV_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_ev_handler(&g_i2c_bus_driver[2]); + mpu_restore(mpu_mode); +} + +void I2C_INSTANCE_2_ER_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_er_handler(&g_i2c_bus_driver[2]); + mpu_restore(mpu_mode); +} +#endif + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/irq.h b/core/embed/trezorhal/stm32f4/irq.h index 319755f1c5a..525bb92043e 100644 --- a/core/embed/trezorhal/stm32f4/irq.h +++ b/core/embed/trezorhal/stm32f4/irq.h @@ -1,50 +1,33 @@ -// clang-format off - /* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) + * This file is part of the Trezor project, https://trezor.io/ * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) SatoshiLabs * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * 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. * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * 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. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ -#ifndef MICROPY_INCLUDED_STM32_IRQ_H -#define MICROPY_INCLUDED_STM32_IRQ_H + +#ifndef TREZORHAL_IRQ_H +#define TREZORHAL_IRQ_H #include STM32_HAL_H #include -// Use this macro together with NVIC_SetPriority to indicate that an IRQn is non-negative, -// which helps the compiler optimise the resulting inline function. -#define IRQn_NONNEG(pri) ((pri) & 0x7f) - -// these states correspond to values from query_irq, enable_irq and disable_irq -#define IRQ_STATE_DISABLED (0x00000001) -#define IRQ_STATE_ENABLED (0x00000000) - -// Enable this to get a count for the number of times each irq handler is called, -// accessible via pyb.irq_stats(). +// Enables simple IRQ statistics for debugging #define IRQ_ENABLE_STATS (0) #if IRQ_ENABLE_STATS -#define IRQ_STATS_MAX (128) +#define IRQ_STATS_MAX (128) extern uint32_t irq_stats[IRQ_STATS_MAX]; #define IRQ_ENTER(irq) ++irq_stats[irq] #define IRQ_EXIT(irq) @@ -53,114 +36,68 @@ extern uint32_t irq_stats[IRQ_STATS_MAX]; #define IRQ_EXIT(irq) #endif -static inline uint32_t query_irq(void) { - return __get_PRIMASK(); -} - -static inline void enable_irq(uint32_t state) { - __set_PRIMASK(state); -} - -static inline uint32_t disable_irq(void) { - uint32_t state = __get_PRIMASK(); - __disable_irq(); - return state; -} - -// enable_irq and disable_irq are defined inline in mpconfigport.h +typedef uint32_t irq_key_t; -#if __CORTEX_M >= 0x03 +// Checks if interrupts are enabled +#define IS_IRQ_ENABLED(key) (((key) & 1) == 0) -// irqs with a priority value greater or equal to "pri" will be disabled -// "pri" should be between 1 and 15 inclusive -static inline uint32_t raise_irq_pri(uint32_t pri) { - uint32_t basepri = __get_BASEPRI(); - // If non-zero, the processor does not process any exception with a - // priority value greater than or equal to BASEPRI. - // When writing to BASEPRI_MAX the write goes to BASEPRI only if either: - // - Rn is non-zero and the current BASEPRI value is 0 - // - Rn is non-zero and less than the current BASEPRI value - pri <<= (8 - __NVIC_PRIO_BITS); - __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); - return basepri; -} - -// "basepri" should be the value returned from raise_irq_pri -static inline void restore_irq_pri(uint32_t basepri) { - __set_BASEPRI(basepri); -} - -#else - -static inline uint32_t raise_irq_pri(uint32_t pri) { - return disable_irq(); -} +// Get the current value of the CPU's exception mask register. +// The least significant bit indicates if interrupts are enabled or disabled. +static inline irq_key_t query_irq(void) { return __get_PRIMASK(); } -// "state" should be the value returned from raise_irq_pri -static inline void restore_irq_pri(uint32_t state) { - enable_irq(state); -} - -#endif - -// IRQ priority definitions. -// -// Lower number implies higher interrupt priority. +// Disables interrupts and returns the previous interrupt state. // -// The default priority grouping is set to NVIC_PRIORITYGROUP_4 in the -// HAL_Init function. This corresponds to 4 bits for the priority field -// and 0 bits for the sub-priority field (which means that for all intensive -// purposes that the sub-priorities below are ignored). +// This function is used to create critical sections by disabling interrupts +// on a Cortex-M platform. It returns the current state of the PRIMASK register, +// which controls the global interrupt enable/disable state. // -// While a given interrupt is being processed, only higher priority (lower number) -// interrupts will preempt a given interrupt. If sub-priorities are active -// then the sub-priority determines the order that pending interrupts of -// a given priority are executed. This is only meaningful if 2 or more -// interrupts of the same priority are pending at the same time. -// -// The priority of the SysTick timer is determined from the TICK_INT_PRIORITY -// value which is normally set to 0 in the stm32f4xx_hal_conf.h file. -// -// The following interrupts are arranged from highest priority to lowest -// priority to make it a bit easier to figure out. - -//#def IRQ_PRI_SYSTICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0) - -// The UARTs have no FIFOs, so if they don't get serviced quickly then characters -// get dropped. The handling for each character only consumes about 0.5 usec -#define IRQ_PRI_UART NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0) - -// SDIO must be higher priority than DMA for SDIO DMA transfers to work. -#define IRQ_PRI_SDIO NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 4, 0) - -// DMA should be higher priority than USB, since USB Mass Storage calls -// into the sdcard driver which waits for the DMA to complete. -#define IRQ_PRI_DMA NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 5, 0) - -// Flash IRQ (used for flushing storage cache) must be at the same priority as -// the USB IRQs, so that the IRQ priority can be raised to this level to disable -// both the USB and cache flushing, when storage transfers are in progress. -#define IRQ_PRI_FLASH NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) - -#define IRQ_PRI_OTG_FS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) -#define IRQ_PRI_OTG_HS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) -#define IRQ_PRI_TIM5 NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) - -#define IRQ_PRI_CAN NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 7, 0) +// Important: +// - The `"memory"` clobber is included to prevent the compiler from reordering +// memory operations across this function, ensuring that all memory accesses +// efore `irq_lock()` are completed before interrupts are disabled. +// - The order of operations on non-volatile variables relative to this +// function is not guaranteed without memory barriers or other +// synchronization mechanisms. +// - When using Link-Time Optimization (LTO), ensure that the behavior of these +// functions is thoroughly tested, as LTO can lead to more aggressive +// optimizations. While GCC typically respects the order of `volatile` +// operations, this is not guaranteed by the C standard. +static inline irq_key_t irq_lock(void) { + uint32_t key; + __asm volatile( + "MRS %0, PRIMASK\n" + "CPSID i" + : "=r"(key) + : + : "memory" // Clobber memory to ensure correct memory operations + ); + return key; +} -#define IRQ_PRI_SPI NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 8, 0) +// Restores the interrupt state to what it was before `irq_lock`. +// +// This function re-enables interrupts based on the PRIMASK state passed to it. +// It should be used in conjunction with `irq_lock` to restore the previous +// interrupt state after a critical section. +static inline void irq_unlock(irq_key_t key) { + __asm volatile( + "MSR PRIMASK, %0\n" + : + : "r"(key) + : "memory" // Clobber memory to ensure correct memory operations + ); +} -// Interrupt priority for non-special timers. -#define IRQ_PRI_TIMX NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 13, 0) +// IRQ priority levels used throughout the system -#define IRQ_PRI_EXTINT NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0) +// Highest priority in the system (only RESET, NMI, and +// HardFault can preempt exceptions at this priority level) +#define IRQ_PRI_HIGHEST NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0) -// PENDSV should be at the lowst priority so that other interrupts complete -// before exception is raised. -#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) -#define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +// Standard priority for common interrupt handlers +#define IRQ_PRI_NORMAL NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 8, 0) -// !@# TAMPER interrupt priority should be probably much higher -#define IRQ_PRI_TAMP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +// Lowest priority in the system used by SVC and PENDSV exception handlers +#define IRQ_PRI_LOWEST NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) -#endif // MICROPY_INCLUDED_STM32_IRQ_H +#endif // TREZORHAL_IRQ_H diff --git a/core/embed/trezorhal/stm32f4/limited_util.s b/core/embed/trezorhal/stm32f4/limited_util.S similarity index 85% rename from core/embed/trezorhal/stm32f4/limited_util.s rename to core/embed/trezorhal/stm32f4/limited_util.S index 0c2f72f8c16..ba510710b0d 100644 --- a/core/embed/trezorhal/stm32f4/limited_util.s +++ b/core/embed/trezorhal/stm32f4/limited_util.S @@ -10,10 +10,13 @@ memset_reg: // 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 .global jump_to @@ -30,13 +33,12 @@ jump_to: cpsid f // wipe memory at the end of the current stage of code bl clear_otg_hs_memory - ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM - ldr r2, =0 // r2 - the word-sized value to be written + ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_handoff_clear_ram_0_start + ldr r1, =_handoff_clear_ram_0_end bl memset_reg - ldr r0, =sram_start // r0 - point to beginning of SRAM - ldr r1, =sram_end // r1 - point to byte after the end of SRAM - ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_handoff_clear_ram_1_start + ldr r1, =_handoff_clear_ram_1_end 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) @@ -87,13 +89,12 @@ shutdown_privileged: mov r11, r0 mov r12, r0 ldr lr, =0xffffffff - ldr r0, =ccmram_start - ldr r1, =ccmram_end - // set to value in r2 + + ldr r0, =_shutdown_clear_ram_0_start + ldr r1, =_shutdown_clear_ram_0_end bl memset_reg - ldr r0, =sram_start - ldr r1, =sram_end - // set to value in r2 + ldr r0, =_shutdown_clear_ram_1_start + ldr r1, =_shutdown_clear_ram_1_end bl memset_reg bl clear_otg_hs_memory ldr r0, =1 diff --git a/core/embed/boardloader/memory_stm32f4.ld b/core/embed/trezorhal/stm32f4/linker/boardloader.ld similarity index 50% rename from core/embed/boardloader/memory_stm32f4.ld rename to core/embed/trezorhal/stm32f4/linker/boardloader.ld index 167d720fba9..6df6bab3c99 100644 --- a/core/embed/boardloader/memory_stm32f4.ld +++ b/core/embed/trezorhal/stm32f4/linker/boardloader.ld @@ -1,30 +1,44 @@ -/* Trezor v2 boardloader linker script */ +INCLUDE "./embed/trezorhal/stm32f4/linker/memory.ld"; ENTRY(reset_handler) MEMORY { - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 48K - CCMRAM (wal) : ORIGIN = 0x10000000, LENGTH = 64K - SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 192K + FLASH (rx) : ORIGIN = BOARDLOADER_START, LENGTH = BOARDLOADER_IMAGE_MAXSIZE + CCMRAM (wal) : ORIGIN = MCU_CCMRAM, LENGTH = MCU_CCMRAM_SIZE + SRAM (wal) : ORIGIN = MCU_SRAM, LENGTH = MCU_SRAM_SIZE } main_stack_base = ORIGIN(CCMRAM) + LENGTH(CCMRAM); /* 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); data_vma = ADDR(.data); data_size = SIZEOF(.data); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* used by the startup code to wipe memory */ -ccmram_start = ORIGIN(CCMRAM); -ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); +_startup_clear_ram_0_start = MCU_CCMRAM; +_startup_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE; +_startup_clear_ram_1_start = MCU_SRAM; +_startup_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; -/* used by the startup code to wipe memory */ -sram_start = ORIGIN(SRAM); -sram_end = ORIGIN(SRAM) + LENGTH(SRAM); +/* used by the startup/jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_CCMRAM; +_handoff_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM; +_handoff_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = MCU_CCMRAM; +_shutdown_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE; +_shutdown_clear_ram_1_start = MCU_SRAM; +_shutdown_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; SECTIONS { - .vector_table : ALIGN(512) { + .vector_table : ALIGN(CODE_ALIGNMENT) { KEEP(*(.vector_table)); } >FLASH AT>FLASH @@ -54,7 +68,7 @@ SECTIONS { } >SRAM /* Hard-coded address for capabilities structure */ - .capabilities 0x0800BF00 : {KEEP(*(.capabilities_section))} + .capabilities BOARD_CAPABILITIES_ADDR : {KEEP(*(.capabilities_section))} .stack : ALIGN(8) { . = 4K; /* this acts as a build time assertion that at least this much memory is available for stack use */ diff --git a/core/embed/bootloader_ci/memory_stm32f4.ld b/core/embed/trezorhal/stm32f4/linker/bootloader.ld similarity index 52% rename from core/embed/bootloader_ci/memory_stm32f4.ld rename to core/embed/trezorhal/stm32f4/linker/bootloader.ld index 42eb1cd20c0..4595adfa41e 100644 --- a/core/embed/bootloader_ci/memory_stm32f4.ld +++ b/core/embed/trezorhal/stm32f4/linker/bootloader.ld @@ -1,12 +1,12 @@ -/* Trezor v2 bootloader linker script */ +INCLUDE "./embed/trezorhal/stm32f4/linker/memory.ld"; ENTRY(reset_handler) MEMORY { - FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 128K - CCMRAM (wal) : ORIGIN = 0x10000000, LENGTH = 64K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x1000FF00, LENGTH = 0x100 - SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 192K + FLASH (rx) : ORIGIN = BOOTLOADER_START, LENGTH = BOOTLOADER_IMAGE_MAXSIZE + CCMRAM (wal) : ORIGIN = MCU_CCMRAM, LENGTH = MCU_CCMRAM_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_CCMRAM + MCU_CCMRAM_SIZE - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM (wal) : ORIGIN = MCU_SRAM, LENGTH = MCU_SRAM_SIZE } main_stack_base = ORIGIN(CCMRAM) + SIZEOF(.stack) ; /* 8-byte aligned full descending stack */ @@ -17,14 +17,26 @@ _estack = main_stack_base; data_lma = LOADADDR(.data); data_vma = ADDR(.data); data_size = SIZEOF(.data); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* used by the startup code to wipe memory */ -ccmram_start = ORIGIN(CCMRAM); -ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); - -/* used by the startup code to wipe memory */ -sram_start = ORIGIN(SRAM); -sram_end = ORIGIN(SRAM) + LENGTH(SRAM); +_startup_clear_ram_0_start = MCU_CCMRAM; +_startup_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE - BOOTARGS_SIZE; +_startup_clear_ram_1_start = MCU_SRAM; +_startup_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; + +/* used by the jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_CCMRAM; +_handoff_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM; +_handoff_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = MCU_CCMRAM; +_shutdown_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE; +_shutdown_clear_ram_1_start = MCU_SRAM; +_shutdown_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); @@ -37,7 +49,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(CODE_ALIGNMENT) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); @@ -67,6 +79,8 @@ SECTIONS { .buf : ALIGN(4) { *(.buf*); . = ALIGN(4); + *(.no_dma_buffers*); + . = ALIGN(4); } >SRAM .boot_args : ALIGN(8) { @@ -74,9 +88,4 @@ SECTIONS { . = ALIGN(8); } >BOOT_ARGS - .data_ccm : ALIGN(4) { - *(.no_dma_buffers*); - . = ALIGN(4); - } >CCMRAM - } diff --git a/core/embed/firmware/memory_T.ld b/core/embed/trezorhal/stm32f4/linker/firmware.ld similarity index 66% rename from core/embed/firmware/memory_T.ld rename to core/embed/trezorhal/stm32f4/linker/firmware.ld index 9affc00a900..64c8b2d11d2 100644 --- a/core/embed/firmware/memory_T.ld +++ b/core/embed/trezorhal/stm32f4/linker/firmware.ld @@ -1,37 +1,26 @@ -/* TREZORv2 firmware linker script */ +INCLUDE "./embed/trezorhal/stm32f4/linker/memory.ld"; ENTRY(reset_handler) MEMORY { - FLASH (rx) : ORIGIN = 0x08040000, LENGTH = 768K - FLASH2 (r) : ORIGIN = 0x08120000, LENGTH = 896K - CCMRAM (wal) : ORIGIN = 0x10000000, LENGTH = 64K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x1000FF00, LENGTH = 0x100 - SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 192K + FLASH (rx) : ORIGIN = FIRMWARE_START, LENGTH = FIRMWARE_P1_IMAGE_MAXSIZE + FLASH2 (r) : ORIGIN = FIRMWARE_P2_START, LENGTH = FIRMWARE_P2_IMAGE_MAXSIZE + CCMRAM (wal) : ORIGIN = MCU_CCMRAM + KERNEL_STACK_SIZE, LENGTH = MCU_CCMRAM_SIZE - KERNEL_CCMRAM_SIZE - KERNEL_FRAMEBUFFER_SIZE - KERNEL_STACK_SIZE + SRAM (wal) : ORIGIN = MCU_SRAM, LENGTH = MCU_SRAM_SIZE - KERNEL_SRAM_SIZE } main_stack_base = ORIGIN(SRAM) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ _sstack = ORIGIN(SRAM); _estack = main_stack_base; +_stack_size = SIZEOF(.stack); /* 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 wipe memory */ -ccmram_start = ORIGIN(CCMRAM); -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); - -/* used by the startup code to wipe memory */ -sram_start = ORIGIN(SRAM); -sram_end = ORIGIN(SRAM) + LENGTH(SRAM); -_ram_start = sram_start; -_ram_end = sram_end; +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); _codelen = LENGTH(FLASH) - SIZEOF(.vendorheader) - SIZEOF(.header) + SIZEOF(.flash2); _flash_start = ORIGIN(FLASH); @@ -48,7 +37,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash2 : ALIGN(512) { + .flash2 : ALIGN(CODE_ALIGNMENT) { build/firmware/frozen_mpy.o(.rodata*); build/firmware/vendor/secp256k1-zkp/src/secp256k1.o(.rodata*); build/firmware/vendor/secp256k1-zkp/src/precomputed_ecmult.o(.rodata*); @@ -62,14 +51,14 @@ SECTIONS { } >FLASH2 AT>FLASH2 .flash : ALIGN(512) { + KEEP(*(.kernel)); + . = ALIGN(512); KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); . = ALIGN(4); *(.rodata*); . = ALIGN(4); - KEEP(*(.bootloader)); - *(.bootloader*); . = ALIGN(512); } >FLASH AT>FLASH @@ -94,7 +83,7 @@ SECTIONS { .heap : ALIGN(4) { . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ - . = ABSOLUTE(sram_end); /* this explicitly sets the end of the heap */ + . = ABSOLUTE(ORIGIN(SRAM) + LENGTH(SRAM)); /* this explicitly sets the end of the heap */ } >SRAM .data_ccm : ALIGN(4) { @@ -102,8 +91,9 @@ SECTIONS { . = ALIGN(4); } >CCMRAM - .boot_args : ALIGN(8) { - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS + + /DISCARD/ : { + *(.ARM.exidx*); + } + } diff --git a/core/embed/trezorhal/stm32f4/linker/kernel.ld b/core/embed/trezorhal/stm32f4/linker/kernel.ld new file mode 100644 index 00000000000..6486ce4cc97 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/linker/kernel.ld @@ -0,0 +1,113 @@ +INCLUDE "./embed/trezorhal/stm32f4/linker/memory.ld"; + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = KERNEL_START, LENGTH = KERNEL_IMAGE_MAXSIZE + CCMRAM_STACK (wal) : ORIGIN = MCU_CCMRAM, LENGTH = KERNEL_STACK_SIZE + CCMRAM_FB (wal) : ORIGIN = MCU_CCMRAM + MCU_CCMRAM_SIZE - KERNEL_CCMRAM_SIZE - KERNEL_FRAMEBUFFER_SIZE, LENGTH = KERNEL_FRAMEBUFFER_SIZE + CCMRAM (wal) : ORIGIN = MCU_CCMRAM + MCU_CCMRAM_SIZE - KERNEL_CCMRAM_SIZE, LENGTH = KERNEL_CCMRAM_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_CCMRAM + MCU_CCMRAM_SIZE - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM (wal) : ORIGIN = MCU_SRAM + MCU_SRAM_SIZE - KERNEL_SRAM_SIZE, LENGTH = KERNEL_SRAM_SIZE +} + +main_stack_base = ORIGIN(CCMRAM_STACK) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(CCMRAM_STACK); +_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); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +/* used by the startup code to wipe memory */ +_startup_clear_ram_0_start = MCU_CCMRAM; +_startup_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE; +_startup_clear_ram_1_start = MCU_SRAM; +_startup_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; + +/* used by the jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_CCMRAM; +_handoff_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE - BOOTARGS_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM; +_handoff_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = MCU_CCMRAM; +_shutdown_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE; +_shutdown_clear_ram_1_start = MCU_SRAM; +_shutdown_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; + +/* used by applet cleaning code */ +_coreapp_clear_ram_0_start = MCU_CCMRAM + KERNEL_STACK_SIZE; +_coreapp_clear_ram_0_size = MCU_CCMRAM_SIZE - KERNEL_CCMRAM_SIZE - KERNEL_FRAMEBUFFER_SIZE - KERNEL_STACK_SIZE; +_coreapp_clear_ram_1_start = MCU_SRAM; +_coreapp_clear_ram_1_size = MCU_SRAM_SIZE - KERNEL_SRAM_SIZE; + + +_codelen = SIZEOF(.vendorheader) + SIZEOF(.header) + SIZEOF(.flash) + SIZEOF(.data) ; +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + . = 1K; + . = ALIGN(CODE_ALIGNMENT); + } >FLASH AT>FLASH + + .flash : ALIGN(CODE_ALIGNMENT) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .stack : ALIGN(8) { + . = 8K; /* Exactly 6k allocated for stack. Overflow causes MemManage fault (when using MPU). */ + } >CCMRAM_STACK + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >CCMRAM AT>FLASH + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >CCMRAM + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM + + .fb : ALIGN(4) { + *(.fb1*); + . = ALIGN(4); + } >CCMRAM_FB + + .boot_args : ALIGN(8) { + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS + + /DISCARD/ : { + *(.ARM.exidx*); + } + +} diff --git a/core/embed/trezorhal/stm32f4/linker/memory.ld b/core/embed/trezorhal/stm32f4/linker/memory.ld new file mode 100644 index 00000000000..edb57837b69 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/linker/memory.ld @@ -0,0 +1,6 @@ + MCU_FLASH_ORIGIN = 0x08000000; + MCU_FLASH_SIZE = 2M; + MCU_CCMRAM = 0x10000000; + MCU_CCMRAM_SIZE = 64K; + MCU_SRAM = 0x20000000; + MCU_SRAM_SIZE = 192K; diff --git a/core/embed/prodtest/memory_stm32f4.ld b/core/embed/trezorhal/stm32f4/linker/prodtest.ld similarity index 51% rename from core/embed/prodtest/memory_stm32f4.ld rename to core/embed/trezorhal/stm32f4/linker/prodtest.ld index 61f7112ba83..2d8f15e94dc 100644 --- a/core/embed/prodtest/memory_stm32f4.ld +++ b/core/embed/trezorhal/stm32f4/linker/prodtest.ld @@ -1,12 +1,12 @@ -/* TREZORv2 firmware linker script */ +INCLUDE "./embed/trezorhal/stm32f4/linker/memory.ld"; ENTRY(reset_handler) MEMORY { - FLASH (rx) : ORIGIN = 0x08040000, LENGTH = 768K - CCMRAM (wal) : ORIGIN = 0x10000000, LENGTH = 64K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x1000FF00, LENGTH = 0x100 - SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 192K + FLASH (rx) : ORIGIN = FIRMWARE_START, LENGTH = FIRMWARE_P1_IMAGE_MAXSIZE + CCMRAM (wal) : ORIGIN = MCU_CCMRAM, LENGTH = MCU_CCMRAM_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_CCMRAM + MCU_CCMRAM_SIZE - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM (wal) : ORIGIN = MCU_SRAM, LENGTH = MCU_SRAM_SIZE } main_stack_base = ORIGIN(SRAM) + LENGTH(SRAM); /* 8-byte aligned full descending stack */ @@ -17,26 +17,34 @@ _estack = main_stack_base; data_lma = LOADADDR(.data); data_vma = ADDR(.data); data_size = SIZEOF(.data); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* used by the startup code to wipe memory */ -ccmram_start = ORIGIN(CCMRAM); -ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); +_startup_clear_ram_0_start = MCU_CCMRAM; +_startup_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE; +_startup_clear_ram_1_start = MCU_SRAM; +_startup_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; + +/* used by the startup/jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_CCMRAM; +_handoff_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE - BOOTARGS_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM; +_handoff_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = MCU_CCMRAM; +_shutdown_clear_ram_0_end = MCU_CCMRAM + MCU_CCMRAM_SIZE; +_shutdown_clear_ram_1_start = MCU_SRAM; +_shutdown_clear_ram_1_end = MCU_SRAM + MCU_SRAM_SIZE; /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); -/* used by the startup code to wipe memory */ -sram_start = ORIGIN(SRAM); -sram_end = ORIGIN(SRAM) + LENGTH(SRAM); -_ram_start = sram_start; -_ram_end = sram_end; - _codelen = SIZEOF(.flash) + SIZEOF(.data); _flash_start = ORIGIN(FLASH); _flash_end = ORIGIN(FLASH) + LENGTH(FLASH); -_heap_start = ADDR(.heap); -_heap_end = ADDR(.heap) + SIZEOF(.heap); SECTIONS { .vendorheader : ALIGN(4) { @@ -47,14 +55,18 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(CODE_ALIGNMENT) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); . = ALIGN(4); *(.rodata*); . = ALIGN(128K); - } >FLASH AT>FLASH + } >FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } .data : ALIGN(4) { *(.data*); @@ -66,11 +78,6 @@ SECTIONS { . = ALIGN(4); } >SRAM - .heap : ALIGN(4) { - . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ - . = ABSOLUTE(sram_end - 16K); /* this explicitly sets the end of the heap effectively giving the stack at most 16K */ - } >SRAM - .stack : ALIGN(8) { . = 4K; /* this acts as a build time assertion that at least this much memory is available for stack use */ } >SRAM diff --git a/core/embed/trezorhal/stm32f4/lowlevel.c b/core/embed/trezorhal/stm32f4/lowlevel.c index 5107522ed11..1174991f193 100644 --- a/core/embed/trezorhal/stm32f4/lowlevel.c +++ b/core/embed/trezorhal/stm32f4/lowlevel.c @@ -20,8 +20,13 @@ #include STM32_HAL_H #include "lowlevel.h" + +#include + #include "flash_otp.h" +#ifdef KERNEL_MODE + #pragma GCC optimize( \ "no-stack-protector") // applies to all functions in this file @@ -80,19 +85,27 @@ secbool flash_check_option_bytes(void) { if (FLASH->OPTCR1 != FLASH_OPTCR1_nWRP) { return secfalse; } + + mpu_mode_t mode = mpu_reconfig(MPU_MODE_FLASHOB); // check values stored in flash memory if ((OPTION_BYTES_RDP_USER & ~3) != OPTION_BYTES_RDP_USER_VALUE) { // bits 0 and 1 are unused + mpu_reconfig(mode); return secfalse; } if ((OPTION_BYTES_BANK1_WRP & 0xCFFFU) != OPTION_BYTES_BANK1_WRP_VALUE) { // bits 12 and 13 are unused + mpu_reconfig(mode); return secfalse; } if ((OPTION_BYTES_BANK2_WRP & 0xFFFU) != OPTION_BYTES_BANK2_WRP_VALUE) { // bits 12, 13, 14, and 15 are unused + mpu_reconfig(mode); return secfalse; } + + mpu_reconfig(mode); + return sectrue; } @@ -186,3 +199,5 @@ secbool reset_flags_check(void) { void reset_flags_reset(void) { RCC->CSR |= RCC_CSR_RMVF; // clear the reset flags } + +#endif // #ifdef KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/monoctr.c b/core/embed/trezorhal/stm32f4/monoctr.c index 4907fc0f953..119b2070bf8 100644 --- a/core/embed/trezorhal/stm32f4/monoctr.c +++ b/core/embed/trezorhal/stm32f4/monoctr.c @@ -20,8 +20,11 @@ #include "monoctr.h" #include "flash_otp.h" #include "model.h" +#include "mpu.h" #include "string.h" +#ifdef KERNEL_MODE + #if !PRODUCTION // we don't want to override OTP on development boards // lets mock this functionality @@ -138,3 +141,5 @@ secbool monoctr_read(monoctr_type_t type, uint8_t* value) { return sectrue; } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/mpu.c b/core/embed/trezorhal/stm32f4/mpu.c index af40d3814db..281bb26b0f6 100644 --- a/core/embed/trezorhal/stm32f4/mpu.c +++ b/core/embed/trezorhal/stm32f4/mpu.c @@ -19,292 +19,368 @@ #include STM32_HAL_H #include TREZOR_BOARD -#include "stm32f4xx_ll_cortex.h" - -// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html -#define MPU_RASR_ATTR_FLASH (MPU_RASR_C_Msk) -#define MPU_RASR_ATTR_SRAM (MPU_RASR_C_Msk | MPU_RASR_S_Msk) -#define MPU_RASR_ATTR_PERIPH (MPU_RASR_B_Msk | MPU_RASR_S_Msk) -#define MPU_SUBREGION_DISABLE(X) ((X) << MPU_RASR_SRD_Pos) +#include +#include -void mpu_config_off(void) { - // Disable MPU - HAL_MPU_Disable(); -} +#include "irq.h" +#include "model.h" +#include "mpu.h" -void mpu_config_boardloader(void) { - // nothing to be done -} +#include "stm32f4xx_ll_cortex.h" -void mpu_config_bootloader(void) { - // Disable MPU - HAL_MPU_Disable(); +#ifdef KERNEL_MODE - // Note: later entries overwrite previous ones - - // Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write) - MPU->RNR = MPU_REGION_NUMBER0; - MPU->RBAR = 0; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_4GB | LL_MPU_REGION_FULL_ACCESS; - - // Flash (0x0800C000 - 0x0800FFFF, 16 KiB, no access) - MPU->RNR = MPU_REGION_NUMBER1; - MPU->RBAR = FLASH_BASE + 0xC000; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_NO_ACCESS; - - // Flash (0x0810C000 - 0x0810FFFF, 16 KiB, no access) - MPU->RNR = MPU_REGION_NUMBER2; - MPU->RBAR = FLASH_BASE + 0x10C000; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_NO_ACCESS; - - // SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end, - // read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER3; - MPU->RBAR = SRAM_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | - LL_MPU_REGION_SIZE_256KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0); - -#ifdef USE_SDRAM - // Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) - // SDRAM (0xC0000000 - 0xDFFFFFFF, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER4; - MPU->RBAR = 0; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH | - LL_MPU_REGION_SIZE_4GB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xBB); -#else - // Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) - // External RAM (0x60000000 - 0x7FFFFFFF, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER4; - MPU->RBAR = PERIPH_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH | - LL_MPU_REGION_SIZE_1GB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk; +// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html +#define MPU_RASR_ATTR_FLASH_CODE (MPU_RASR_C_Msk) +#define MPU_RASR_ATTR_FLASH_DATA (MPU_RASR_C_Msk | MPU_RASR_XN_Msk) +#define MPU_RASR_ATTR_SRAM (MPU_RASR_C_Msk | MPU_RASR_S_Msk | MPU_RASR_XN_Msk) +#define MPU_RASR_ATTR_PERIPH (MPU_RASR_B_Msk | MPU_RASR_S_Msk | MPU_RASR_XN_Msk) + +#define SET_REGION(region, start, size, mask, attr, access) \ + do { \ + uint32_t _enable = MPU_RASR_ENABLE_Msk; \ + uint32_t _size = LL_MPU_REGION_##size; \ + uint32_t _mask = (mask) << MPU_RASR_SRD_Pos; \ + uint32_t _attr = MPU_RASR_ATTR_##attr; \ + uint32_t _access = LL_MPU_REGION_##access; \ + MPU->RNR = region; \ + MPU->RBAR = (start) & ~0x1F; \ + MPU->RASR = _enable | _size | _mask | _attr | _access; \ + } while (0) + +#define DIS_REGION(region) \ + do { \ + MPU->RNR = region; \ + MPU->RBAR = 0; \ + MPU->RASR = 0; \ + } while (0) + +typedef struct { + // Set if the driver is initialized + bool initialized; + // Current mode + mpu_mode_t mode; + +} mpu_driver_t; + +mpu_driver_t g_mpu_driver = { + .initialized = false, + .mode = MPU_MODE_DISABLED, +}; + +#define SRAM_SIZE (192 * 1024) + +#define KERNEL_STACK_START (CCMDATARAM_BASE) +#define KERNEL_CCMRAM_START (CCMDATARAM_END + 1 - KERNEL_CCMRAM_SIZE) +#define KERNEL_SRAM_START (SRAM1_BASE + SRAM_SIZE - KERNEL_SRAM_SIZE) + +#define KERNEL_CCMRAM_FB_START (KERNEL_CCMRAM_START - KERNEL_FRAMEBUFFER_SIZE) + +static void mpu_init_fixed_regions(void) { + // Regions #0 to #4 are fixed for all targets + +#ifdef BOARDLOADER + // clang-format off + // Code in the Flash Bank #1 (Unprivileged, Read-Only, Executable) + // Subregion: 48KB = 64KB except 2/8 at end + SET_REGION( 0, BOARDLOADER_START, SIZE_64KB, 0xC0, FLASH_CODE, PRIV_RO_URO ); + // Rest of the code in the Flash Bank #1 (Unprivileged, Read-Only) + // Subregion: 896KB = 1024KB except 1/8 at start + SET_REGION( 1, FLASH_BASE, SIZE_1MB, 0x01, FLASH_DATA, FULL_ACCESS ); + // Rest of the code in the Flash Bank #2 (Unprivileged, Read-Only) + // Subregion: 896KB = 1024KB except 1/8 at start + SET_REGION( 2, FLASH_BASE + 0x100000, SIZE_1MB, 0x01, FLASH_DATA, FULL_ACCESS ); + // All CCMRAM (Unprivileged, Read-Write, Non-Executable) + SET_REGION( 3, CCMDATARAM_BASE, SIZE_64KB, 0x00, SRAM, FULL_ACCESS ); + // All SRAM (Unprivileged, Read-Write, Non-Executable) + // Subregion: 192KB = 256KB except 2/8 at end + SET_REGION( 4, SRAM_BASE, SIZE_256KB, 0xC0, SRAM, FULL_ACCESS ); + // clang-format on #endif - -#if defined STM32F427xx || defined STM32F429xx - // CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER5; - MPU->RBAR = CCMDATARAM_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | - LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk; -#elif STM32F405xx - // no CCMRAM -#else -#error Unsupported MCU +#ifdef BOOTLOADER + // clang-format off + // Bootloader code in the Flash Bank #1 (Unprivileged, Read-Only, Executable) + // Subregion: 128KB = 1024KB except 2/8 at start + SET_REGION( 0, BOOTLOADER_START, SIZE_128KB, 0x00, FLASH_CODE, PRIV_RO_URO ); + // Kernel/coreapp code in the Flash Bank #1 (Unprivileged, Read-Only) + // Subregion: 768KB = 1024KB except 2/8 at start + SET_REGION( 1, FLASH_BASE, SIZE_1MB, 0x03, FLASH_DATA, FULL_ACCESS ); + // Kernel/coreapp code in the Flash Bank #2 (Unprivileged, Read-Only) + // Subregion: 896KB = 1024KB except 1/8 at start + SET_REGION( 2, FLASH_BASE + 0x100000, SIZE_1MB, 0x01, FLASH_DATA, FULL_ACCESS ); + // All CCMRAM (Unprivileged, Read-Write, Non-Executable) + SET_REGION( 3, CCMDATARAM_BASE, SIZE_64KB, 0x00, SRAM, FULL_ACCESS ); + // All SRAM (Unprivileged, Read-Write, Non-Executable) + // Subregion: 192KB = 256KB except 2/8 at end + SET_REGION( 4, SRAM_BASE, SIZE_256KB, 0xC0, SRAM, FULL_ACCESS ); + // clang-format on +#endif +#ifdef KERNEL + // clang-format off + // Code in the Flash Bank #1 (Unprivileged, Read-Only, Executable) + // Subregion: 768KB = 1024KB except 2/8 at start + SET_REGION( 0, FLASH_BASE, SIZE_1MB, 0x03, FLASH_CODE, PRIV_RO_URO ); + // Code in the Flash Bank #2 (Unprivileged, Read-Only, Executable) + // Subregion: 896KB = 1024KB except 1/8 at start + SET_REGION( 1, FLASH_BASE + 0x100000, SIZE_1MB, 0x01, FLASH_CODE, PRIV_RO_URO ); + // All CCMRAM (Unprivileged, Read-Write, Non-Executable) + SET_REGION( 2, CCMDATARAM_BASE, SIZE_64KB, 0x00, SRAM, FULL_ACCESS ); + // All SRAM (Unprivileged, Read-Write, Non-Executable) + // Subregion: 192KB = 256KB except 2/8 at end + SET_REGION( 3, SRAM_BASE, SIZE_256KB, 0xC0, SRAM, FULL_ACCESS ); + // Kernel CCMRAM (Privileged, Read-Write, Non-Executable) + // SubRegion: 8KB at the beginning + 16KB at the end of 64KB CCMRAM + SET_REGION( 4, CCMDATARAM_BASE, SIZE_64KB, 0x3E, SRAM, PRIV_RW ); + // clang-format on +#endif +#ifdef FIRMWARE + // clang-format off + // Code in the Flash Bank #1 (Unprivileged, Read-Only, Executable) + // Subregion: 768KB = 1024KB except 2/8 at start + SET_REGION( 0, FLASH_BASE, SIZE_1MB, 0x03, FLASH_CODE, PRIV_RO_URO ); + // Code in the Flash Bank #2 (Unprivileged, Read-Only, Executable) + // Subregion: 896KB = 1024KB except 1/8 at start + SET_REGION( 1, FLASH_BASE + 0x100000, SIZE_1MB, 0x01, FLASH_CODE, PRIV_RO_URO ); + // All CCMRAM (Unprivileged, Read-Write, Non-Executable) + SET_REGION( 2, CCMDATARAM_BASE, SIZE_64KB, 0x00, SRAM, FULL_ACCESS ); + // All SRAM (Unprivileged, Read-Write, Non-Executable) + // Subregion: 192KB = 256KB except 2/8 at end + SET_REGION( 3, SRAM_BASE, SIZE_256KB, 0xC0, SRAM, FULL_ACCESS ); + DIS_REGION( 4 ); + // clang-format on +#endif +#ifdef TREZOR_PRODTEST + // clang-format off + // Code in the Flash Bank #1 (Unprivileged, Read-Only, Executable) + // Subregion: 768KB = 1024KB except 2/8 at start + SET_REGION( 0, FLASH_BASE, SIZE_1MB, 0x03, FLASH_CODE, PRIV_RO_URO ); + // Code in the Flash Bank #2 (Unprivileged, Read-Only, Executable) + // Subregion: 896KB = 1024KB except 1/8 at start + SET_REGION( 1, FLASH_BASE + 0x100000, SIZE_1MB, 0x01, FLASH_CODE, PRIV_RO_URO ); + // All CCMRAM (Unprivileged, Read-Write, Non-Executable) + SET_REGION( 2, CCMDATARAM_BASE, SIZE_64KB, 0x00, SRAM, FULL_ACCESS ); + // All SRAM (Unprivileged, Read-Write, Non-Executable) + // Subregion: 192KB = 256KB except 2/8 at end + SET_REGION( 3, SRAM_BASE, SIZE_256KB, 0xC0, SRAM, FULL_ACCESS ); + // Firmware header (Unprivileged, Read-Write, Non-Executable) + // (used in production test to invalidate the firmware) + SET_REGION( 4, FIRMWARE_START, SIZE_1KB, 0x00, FLASH_DATA, PRIV_RW_URO ); + // clang-format on #endif - // Enable MPU - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + // Regions #5 to #7 are banked + DIS_REGION(5); + DIS_REGION(6); + DIS_REGION(7); } -void mpu_config_firmware_initial(void) {} +void mpu_init(void) { + mpu_driver_t* drv = &g_mpu_driver; -void mpu_config_firmware(void) { - // Disable MPU - HAL_MPU_Disable(); + if (drv->initialized) { + return; + } - // Note: later entries overwrite previous ones + irq_key_t irq_key = irq_lock(); - /* - // Boardloader (0x08000000 - 0x0800FFFF, 64 KiB, read-only, execute never) - MPU->RBAR = FLASH_BASE | MPU_REGION_NUMBER0; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO | MPU_RASR_XN_Msk; - */ + HAL_MPU_Disable(); - // Bootloader (0x08020000 - 0x0803FFFF, 128 KiB, read-only) - MPU->RNR = MPU_REGION_NUMBER0; - MPU->RBAR = FLASH_BASE + 0x20000; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_128KB | LL_MPU_REGION_PRIV_RO_URO; + mpu_init_fixed_regions(); - // Storage#1 (0x08010000 - 0x0801FFFF, 64 KiB, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER1; - MPU->RBAR = FLASH_BASE + 0x10000; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk; + drv->mode = MPU_MODE_DISABLED; + drv->initialized = true; -#ifdef USE_OPTIGA - // Translations + Storage#2 - secret (0x08104000 - 0x0811FFFF, 112 KiB, - // read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER2; - MPU->RBAR = FLASH_BASE + 0x100000; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_128KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0x01); -#else - // Translations + Storage#2 (0x08100000 - 0x0811FFFF, 128 KiB, read-write, - // execute never) - MPU->RNR = MPU_REGION_NUMBER2; - MPU->RBAR = FLASH_BASE + 0x100000; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_128KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk; -#endif + irq_unlock(irq_key); +} - // Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at - // start = 768 KiB, read-only) - MPU->RNR = MPU_REGION_NUMBER3; - MPU->RBAR = FLASH_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_PRIV_RO_URO | - MPU_SUBREGION_DISABLE(0x03); - - // Firmware extra (0x08120000 - 0x081FFFFF, 7 * 128 KiB = 1024 KiB except 1/8 - // at start = 896 KiB, read-only) - MPU->RNR = MPU_REGION_NUMBER4; - MPU->RBAR = FLASH_BASE + 0x100000; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_PRIV_RO_URO | - MPU_SUBREGION_DISABLE(0x01); - - // SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end, - // read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER5; - MPU->RBAR = SRAM_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | - LL_MPU_REGION_SIZE_256KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0); - -#ifdef USE_SDRAM - // Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) - // SDRAM (0xC0000000 - 0xDFFFFFFF, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER6; - MPU->RBAR = 0; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH | - LL_MPU_REGION_SIZE_4GB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xBB); -#else - // Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) - // External RAM (0x60000000 - 0x7FFFFFFF, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER6; - MPU->RBAR = PERIPH_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH | - LL_MPU_REGION_SIZE_1GB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk; -#endif +mpu_mode_t mpu_get_mode(void) { + mpu_driver_t* drv = &g_mpu_driver; -#if defined STM32F427xx || defined STM32F429xx - // CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER7; - MPU->RBAR = CCMDATARAM_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | - LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk; -#elif STM32F405xx - // no CCMRAM -#else -#error Unsupported MCU -#endif - - // Enable MPU - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + if (!drv->initialized) { + return MPU_MODE_DISABLED; + } - __asm__ volatile("dsb"); - __asm__ volatile("isb"); + return drv->mode; } -void mpu_config_prodtest_initial(void) {} +// STM32F4xx memory map +// +// 0x08000000 2MB FLASH +// 0x10000000 64KB CCMRAM +// 0x1FFF7800 528B OTP +// 0x20000000 192KB SRAM +// 0x40000000 512MB PERIPH + +// STM32F4xx flash layout +// +// 0x08000000 4x 16KB (BANK #1) +// 0x08010000 1x 64KB (BANK #1) +// 0x08020000 7x 128KB (BANK #1) +// 0x08100000 4x 16KB (BANK #2) +// 0x08110000 1x 64KB (BANK #3) +// 0x08120000 7x 128KB (BANK #4) + +mpu_mode_t mpu_reconfig(mpu_mode_t mode) { + mpu_driver_t* drv = &g_mpu_driver; + + if (!drv->initialized) { + // Solves the issue when some IRQ handler tries to reconfigure + // MPU before it is initialized + return MPU_MODE_DISABLED; + } + + irq_key_t irq_key = irq_lock(); -void mpu_config_prodtest(void) { - // Disable MPU HAL_MPU_Disable(); - // Note: later entries overwrite previous ones - - // // Boardloader (0x08000000 - 0x0800BFFF, 48 KiB, read-only, execute never) - // MPU->RNR = MPU_REGION_NUMBER0; - // MPU->RBAR = FLASH_BASE; - // MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - // LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO | - // MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0); - - // Secret area (0x08100000 - 0x08103FFF, 16 KiB, read-write, execute never) - // MPU->RNR = MPU_REGION_NUMBER0; - // MPU->RBAR = FLASH_BASE + 0x100000; - // MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - // LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_FULL_ACCESS | - // MPU_RASR_XN_Msk; - - // Bootloader (0x08020000 - 0x0803FFFF, 64 KiB, read-only) - MPU->RNR = MPU_REGION_NUMBER1; - MPU->RBAR = FLASH_BASE + 0x20000; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO; - - // Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at - // start = 768 KiB, read-only) - MPU->RNR = MPU_REGION_NUMBER2; - MPU->RBAR = FLASH_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_FULL_ACCESS | - MPU_SUBREGION_DISABLE(0x03); - - // Firmware extra (0x08120000 - 0x081FFFFF, 7 * 128 KiB = 1024 KiB except 1/8 - // at start = 896 KiB, read-only) - MPU->RNR = MPU_REGION_NUMBER3; - MPU->RBAR = FLASH_BASE + 0x100000; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_FULL_ACCESS | - MPU_SUBREGION_DISABLE(0x01); - - // SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end, - // read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER4; - MPU->RBAR = SRAM_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | - LL_MPU_REGION_SIZE_256KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0); - -#ifdef USE_SDRAM - // Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) - // SDRAM (0xC0000000 - 0xDFFFFFFF, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER5; - MPU->RBAR = 0; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH | - LL_MPU_REGION_SIZE_4GB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xBB); + // Region #5 and #6 are banked + + // clang-format off + switch (mode) { +#if !defined(BOARDLOADER) + case MPU_MODE_BOARDCAPS: + DIS_REGION( 5 ); + // Boardloader (Privileged, Read-Only, Non-Executable) + // Subregion: 48KB = 64KB except 2/8 at end + SET_REGION( 6, FLASH_BASE, SIZE_64KB, 0xC0, FLASH_DATA, PRIV_RO ); + break; +#endif + +#if !defined(BOARDLOADER) && !defined(BOOTLOADER) + case MPU_MODE_BOOTUPDATE: + DIS_REGION( 5 ); + // Bootloader (Privileged, Read-Write, Non-Executable) + SET_REGION( 6, FLASH_BASE + 0x20000, SIZE_128KB, 0x00, FLASH_DATA, PRIV_RW ); + break; +#endif + + case MPU_MODE_OTP: + DIS_REGION( 5 ); + // OTP (Privileged, Read-Write, Non-Executable) + SET_REGION( 6, FLASH_OTP_BASE, SIZE_1KB, 0x00, FLASH_DATA, FULL_ACCESS ); + break; + + case MPU_MODE_FSMC_REGS: + DIS_REGION( 5 ); + // FSMC Control Registers (Privileged, Read-Write, Non-Executable) + // 0xA0000000 = FMSC_R_BASE (not defined in used headers) + SET_REGION( 6, 0xA0000000, SIZE_4KB, 0x00, FLASH_DATA, FULL_ACCESS ); + break; + + case MPU_MODE_FLASHOB: + SET_REGION( 5, 0x1FFFC000, SIZE_1KB, 0x00, FLASH_DATA, PRIV_RO ); + SET_REGION( 6, 0x1FFEC000, SIZE_1KB, 0x00, FLASH_DATA, PRIV_RO ); + break; + + case MPU_MODE_STORAGE: + // Storage in the Flash Bank #1 (Privileged, Read-Write, Non-Executable) + SET_REGION( 5, FLASH_BASE + 0x10000, SIZE_64KB, 0x00, FLASH_DATA, PRIV_RW ); + // Storage in the Flash Bank #2 (Privileged, Read-Write, Non-Executable) + SET_REGION( 6, FLASH_BASE + 0x110000, SIZE_64KB, 0x00, FLASH_DATA, PRIV_RW ); + break; + + case MPU_MODE_KERNEL_SRAM: + DIS_REGION( 5 ); + // Kernel data in DMA accessible SRAM (Privileged, Read-Write, Non-Executable) + // (overlaps with unprivileged SRAM region) + SET_REGION( 6, SRAM_BASE, SIZE_1KB, 0x00, SRAM, PRIV_RW ); + break; + + case MPU_MODE_UNUSED_FLASH: + // Unused Flash Area #1 (Privileged, Read-Write, Non-Executable) + SET_REGION( 5, FLASH_BASE + 0x00C000, SIZE_16KB, 0x00, FLASH_DATA, PRIV_RW ); + // Unused Flash Area #2 (Privileged, Read-Write, Non-Executable) + SET_REGION( 6, FLASH_BASE + 0x10C000, SIZE_16KB, 0x00, FLASH_DATA, PRIV_RW ); + break; + +#ifdef USE_OPTIGA + // with optiga, we use the secret sector, and assets area is smaller + case MPU_MODE_SECRET: + DIS_REGION( 5 ); + // Secret sector in Bank #2 (Privileged, Read-Write, Non-Executable) + SET_REGION( 6, FLASH_BASE + 0x100000, SIZE_16KB, 0x00, FLASH_DATA, PRIV_RW ); + break; + + case MPU_MODE_ASSETS: + DIS_REGION( 5 ); + // Assets (Privileged, Read-Write, Non-Executable) + // Subregion: 32KB = 64KB except 2/8 at start and 2/8 at end + SET_REGION( 6, FLASH_BASE + 0x104000, SIZE_64KB, 0xC3, FLASH_DATA, PRIV_RW ); + break; + + case MPU_MODE_APP: + // Kernel data in DMA accessible SRAM (Privileged, Read-Write, Non-Executable) + // (overlaps with unprivileged SRAM region) + SET_REGION( 5, SRAM_BASE, SIZE_1KB, 0x00, SRAM, PRIV_RW ); + // Assets (Unprivileged, Read-Only, Non-Executable) + // Subregion: 32KB = 64KB except 2/8 at start and 2/8 at end + SET_REGION( 6, FLASH_BASE + 0x104000, SIZE_64KB, 0xC3, FLASH_DATA, PRIV_RO_URO ); + break; + #else - // Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) - // External RAM (0x60000000 - 0x7FFFFFFF, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER5; - MPU->RBAR = PERIPH_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH | - LL_MPU_REGION_SIZE_1GB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk; + // without optiga, we use additional sector for assets area + case MPU_MODE_ASSETS: + DIS_REGION( 5 ); + // Assets (Privileged, Read-Write, Non-Executable) + // Subregion: 48KB = 64KB except 2/8 at end + SET_REGION( 6, FLASH_BASE + 0x100000, SIZE_64KB, 0xC0, FLASH_DATA, PRIV_RW ); + break; + + case MPU_MODE_APP: + // Kernel data in DMA accessible SRAM (Privileged, Read-Write, Non-Executable) + // (overlaps with unprivileged SRAM region) + SET_REGION( 5, SRAM_BASE, SIZE_1KB, 0x00, SRAM, PRIV_RW ); + // Assets (Unprivileged, Read-Only, Non-Executable) + // Subregion: 48KB = 64KB except 2/8 at end + SET_REGION( 6, FLASH_BASE + 0x100000, SIZE_64KB, 0xC0, FLASH_DATA, PRIV_RO_URO ); + break; + #endif -#if defined STM32F427xx || defined STM32F429xx - // CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER6; - MPU->RBAR = CCMDATARAM_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | - LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk; -#elif STM32F405xx - // no CCMRAM + default: + DIS_REGION( 5 ); + DIS_REGION( 6 ); + break; + } + // clang-format on + + // Region #7 is banked + + // clang-format off + switch (mode) { +#ifdef TREZOR_MODEL_DISC1 + default: + // All Peripherals (Unprivileged, Read-Write, Non-Executable) + // SDRAM + SET_REGION( 7, 0x00000000, SIZE_4GB, 0xBB, SRAM, FULL_ACCESS ); + break; #else -#error Unsupported MCU + case MPU_MODE_APP: + // Dma2D (Unprivileged, Read-Write, Non-Executable) + // 3KB = 4KB except 1/4 at end + SET_REGION( 7, 0x4002B000, SIZE_4KB, 0xC0, PERIPH, FULL_ACCESS ); + break; + default: + // All Peripherals (Privileged, Read-Write, Non-Executable) + SET_REGION( 7, PERIPH_BASE, SIZE_1GB, 0x00, PERIPH, PRIV_RW ); + break; #endif + } + // clang-format on + + if (mode != MPU_MODE_DISABLED) { + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + } - // OTP (0x1FFF7800 - 0x1FFF7C00, read-write, execute never) - MPU->RNR = MPU_REGION_NUMBER7; - MPU->RBAR = FLASH_OTP_BASE; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_1KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk; + mpu_mode_t prev_mode = drv->mode; + drv->mode = mode; - // Enable MPU - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + irq_unlock(irq_key); - __asm__ volatile("dsb"); - __asm__ volatile("isb"); + return prev_mode; } + +void mpu_restore(mpu_mode_t mode) { mpu_reconfig(mode); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/optiga_hal.c b/core/embed/trezorhal/stm32f4/optiga_hal.c index ec7a3091196..b3d659fcf13 100644 --- a/core/embed/trezorhal/stm32f4/optiga_hal.c +++ b/core/embed/trezorhal/stm32f4/optiga_hal.c @@ -2,6 +2,8 @@ #include "common.h" #include TREZOR_BOARD +#ifdef KERNEL_MODE + void optiga_hal_init(void) { OPTIGA_RST_CLK_EN(); // init reset pin @@ -27,3 +29,5 @@ void optiga_reset(void) { // warm reset startup time min 15ms hal_delay(20); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/platform.c b/core/embed/trezorhal/stm32f4/platform.c index e7323d40337..8d801d507fd 100644 --- a/core/embed/trezorhal/stm32f4/platform.c +++ b/core/embed/trezorhal/stm32f4/platform.c @@ -21,8 +21,11 @@ #include "platform.h" #include "rng.h" +#include "systick.h" #include TREZOR_BOARD +#ifdef KERNEL_MODE + const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; @@ -193,7 +196,7 @@ void set_core_clock(clock_settings_t settings) { /* Enable PLL as main clock */ RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_SW)) | RCC_CFGR_SW_PLL; - HAL_InitTick(TICK_INT_PRIORITY); + systick_update_freq(); // turn off the HSI as it is now unused (it will be turned on again // automatically if a clock security failure occurs) @@ -204,19 +207,4 @@ void set_core_clock(clock_settings_t settings) { } #endif -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_IRQHandler(void) { -#ifdef BACKLIGHT_PWM_TIM - BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = 0; // turn off display backlight -#endif - shutdown_privileged(); -} +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/platform.h b/core/embed/trezorhal/stm32f4/platform.h index 71071276166..c7314654463 100644 --- a/core/embed/trezorhal/stm32f4/platform.h +++ b/core/embed/trezorhal/stm32f4/platform.h @@ -35,9 +35,7 @@ void set_core_clock(clock_settings_t settings); void memset_reg(volatile void *start, volatile void *stop, uint32_t val); void jump_to(uint32_t address); void jump_to_with_flag(uint32_t address, uint32_t register_flag); -void ensure_compatible_settings(void); void clear_otg_hs_memory(void); -void drop_privileges(void); extern uint32_t __stack_chk_guard; diff --git a/core/embed/trezorhal/stm32f4/random_delays.c b/core/embed/trezorhal/stm32f4/random_delays.c index 7a27cc4eb0e..9dbbe0a9d53 100644 --- a/core/embed/trezorhal/stm32f4/random_delays.c +++ b/core/embed/trezorhal/stm32f4/random_delays.c @@ -44,6 +44,9 @@ Random Delays in Embedded Software by Michael Tunstall, Olivier Benoit: #include "common.h" #include "memzero.h" #include "rand.h" +#include "systimer.h" + +#ifdef KERNEL_MODE // from util.s extern void shutdown_privileged(void); @@ -151,7 +154,16 @@ static void wait(uint32_t delay) { : "r0", "r1"); } -void random_delays_init() { drbg_init(); } +// forward declaration +static void rdi_handler(void *context); + +void rdi_init() { + drbg_init(); + + systimer_t *timer = systimer_create(rdi_handler, NULL); + ensure(sectrue * (timer != NULL), "rdi_init failed"); + systimer_set_periodic(timer, 1); +} void rdi_start(void) { ensure(drbg_initialized, NULL); @@ -174,7 +186,7 @@ void rdi_refresh_session_delay(void) { refresh_session_delay = true; } -void rdi_handler(uint32_t uw_tick) { +static void rdi_handler(void *context) { if (rdi_disabled == secfalse) { // if rdi enabled if (refresh_session_delay) { session_delay = drbg_random8(); @@ -210,3 +222,5 @@ void wait_random(void) { } #endif } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/rgb_led.c b/core/embed/trezorhal/stm32f4/rgb_led.c index a6e8768d2f2..8d0fbd37990 100644 --- a/core/embed/trezorhal/stm32f4/rgb_led.c +++ b/core/embed/trezorhal/stm32f4/rgb_led.c @@ -39,6 +39,8 @@ #include "common.h" +#ifdef KERNEL_MODE + #include STM32_HAL_H #define RESET_DATA_LEN 18 // >80us no pulse before sending data @@ -166,3 +168,5 @@ void rgb_led_init(void) { // turns off the LED rgb_led_set_color(0x000000); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/rng.c b/core/embed/trezorhal/stm32f4/rng.c index 29a98c12189..a6ae2b57c3c 100644 --- a/core/embed/trezorhal/stm32f4/rng.c +++ b/core/embed/trezorhal/stm32f4/rng.c @@ -21,6 +21,8 @@ #include "rng.h" +#if KERNEL_MODE + #pragma GCC optimize( \ "no-stack-protector") // applies to all functions in this file @@ -56,3 +58,5 @@ uint32_t rng_get(void) { current = rng_read(previous, 1); return current; } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/sdcard.c b/core/embed/trezorhal/stm32f4/sdcard.c index 75d46a9a818..386ccef0369 100644 --- a/core/embed/trezorhal/stm32f4/sdcard.c +++ b/core/embed/trezorhal/stm32f4/sdcard.c @@ -49,9 +49,11 @@ #include #include "irq.h" +#include "mpu.h" #include "sdcard-set_clr_card_detect.h" #include "sdcard.h" -#include "supervise.h" + +#ifdef KERNEL_MODE #define SDMMC_CLK_ENABLE() __HAL_RCC_SDMMC1_CLK_ENABLE() #define SDMMC_CLK_DISABLE() __HAL_RCC_SDMMC1_CLK_DISABLE() @@ -62,9 +64,9 @@ static DMA_HandleTypeDef sd_dma = {0}; void DMA2_Stream3_IRQHandler(void) { IRQ_ENTER(DMA2_Stream3_IRQn); - + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); HAL_DMA_IRQHandler(&sd_dma); - + mpu_restore(mpu_mode); IRQ_EXIT(DMA2_Stream3_IRQn); } @@ -134,8 +136,8 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { SDMMC_CLK_ENABLE(); // NVIC configuration for SDIO interrupts - svc_setpriority(SDMMC_IRQn, IRQ_PRI_SDIO); - svc_enableIRQ(SDMMC_IRQn); + NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(SDMMC_IRQn); } // GPIO have already been initialised by sdcard_init @@ -143,7 +145,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { if (hsd->Instance == sd_handle.Instance) { - svc_disableIRQ(SDMMC_IRQn); + NVIC_DisableIRQ(SDMMC_IRQn); SDMMC_CLK_DISABLE(); } } @@ -232,9 +234,11 @@ uint64_t sdcard_get_capacity_in_bytes(void) { void SDIO_IRQHandler(void) { IRQ_ENTER(SDIO_IRQn); + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); if (sd_handle.Instance) { HAL_SD_IRQHandler(&sd_handle); } + mpu_restore(mpu_mode); IRQ_EXIT(SDIO_IRQn); } @@ -254,13 +258,13 @@ static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t start = HAL_GetTick(); for (;;) { // Do an atomic check of the state; WFI will exit even if IRQs are disabled - uint32_t irq_state = disable_irq(); + irq_key_t irq_key = irq_lock(); if (sd->State != HAL_SD_STATE_BUSY) { - enable_irq(irq_state); + irq_unlock(irq_key); break; } __WFI(); - enable_irq(irq_state); + irq_unlock(irq_key); if (HAL_GetTick() - start >= timeout) { return HAL_TIMEOUT; } @@ -298,9 +302,6 @@ secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num, HAL_StatusTypeDef err = HAL_OK; - // we must disable USB irqs to prevent MSC contention with SD card - uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - sd_dma.Instance = DMA2_Stream3; sd_dma.State = HAL_DMA_STATE_RESET; sd_dma.Init.Channel = DMA_CHANNEL_4; @@ -327,7 +328,7 @@ secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num, DMA_HandleTypeDef dummy_dma = {0}; sd_handle.hdmatx = &dummy_dma; - svc_enableIRQ(DMA2_Stream3_IRQn); + NVIC_EnableIRQ(DMA2_Stream3_IRQn); sdcard_reset_periph(); err = @@ -336,12 +337,10 @@ secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num, err = sdcard_wait_finished(&sd_handle, 5000); } - svc_disableIRQ(DMA2_Stream3_IRQn); + NVIC_DisableIRQ(DMA2_Stream3_IRQn); HAL_DMA_DeInit(&sd_dma); sd_handle.hdmarx = NULL; - restore_irq_pri(basepri); - return sectrue * (err == HAL_OK); } @@ -359,9 +358,6 @@ secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, HAL_StatusTypeDef err = HAL_OK; - // we must disable USB irqs to prevent MSC contention with SD card - uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - sd_dma.Instance = DMA2_Stream3; sd_dma.State = HAL_DMA_STATE_RESET; sd_dma.Init.Channel = DMA_CHANNEL_4; @@ -388,7 +384,7 @@ secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, DMA_HandleTypeDef dummy_dma = {0}; sd_handle.hdmarx = &dummy_dma; - svc_enableIRQ(DMA2_Stream3_IRQn); + NVIC_EnableIRQ(DMA2_Stream3_IRQn); sdcard_reset_periph(); err = @@ -397,11 +393,11 @@ secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, err = sdcard_wait_finished(&sd_handle, 5000); } - svc_disableIRQ(DMA2_Stream3_IRQn); + NVIC_DisableIRQ(DMA2_Stream3_IRQn); HAL_DMA_DeInit(&sd_dma); sd_handle.hdmatx = NULL; - restore_irq_pri(basepri); - return sectrue * (err == HAL_OK); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/sdram.c b/core/embed/trezorhal/stm32f4/sdram.c index 0c9102d63c4..3cc9360f4ed 100644 --- a/core/embed/trezorhal/stm32f4/sdram.c +++ b/core/embed/trezorhal/stm32f4/sdram.c @@ -16,9 +16,12 @@ * ****************************************************************************** */ +#ifdef KERNEL_MODE /* Includes ------------------------------------------------------------------*/ #include "sdram.h" +#include "irq.h" +#include "mpu.h" /** @addtogroup BSP * @{ @@ -89,6 +92,8 @@ void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params); void sdram_init(void) { static uint8_t sdramstatus = SDRAM_ERROR; + mpu_mode_t mode = mpu_reconfig(MPU_MODE_FSMC_REGS); + /* SDRAM device configuration */ SdramHandle.Instance = FMC_SDRAM_DEVICE; @@ -136,6 +141,8 @@ void sdram_init(void) { /* SDRAM initialization sequence */ BSP_SDRAM_Initialization_sequence(REFRESH_COUNT); + mpu_restore(mode); + (void)sdramstatus; } @@ -397,8 +404,8 @@ void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params) { HAL_DMA_Init(&dmaHandle); /* NVIC configuration for DMA transfer complete interrupt */ - HAL_NVIC_SetPriority(SDRAM_DMAx_IRQn, 0x0F, 0); - HAL_NVIC_EnableIRQ(SDRAM_DMAx_IRQn); + NVIC_SetPriority(SDRAM_DMAx_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(SDRAM_DMAx_IRQn); } /* of if(hsdram != (SDRAM_HandleTypeDef *)NULL) */ } @@ -413,7 +420,7 @@ void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params) { if (hsdram != (SDRAM_HandleTypeDef *)NULL) { /* Disable NVIC configuration for DMA interrupt */ - HAL_NVIC_DisableIRQ(SDRAM_DMAx_IRQn); + NVIC_DisableIRQ(SDRAM_DMAx_IRQn); /* Deinitialize the stream for new transfer */ dma_handle.Instance = SDRAM_DMAx_STREAM; @@ -443,3 +450,5 @@ void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params) { /** * @} */ + +#endif diff --git a/core/embed/trezorhal/stm32f4/secret.c b/core/embed/trezorhal/stm32f4/secret.c index 72a3aefc012..175cb253966 100644 --- a/core/embed/trezorhal/stm32f4/secret.c +++ b/core/embed/trezorhal/stm32f4/secret.c @@ -4,10 +4,9 @@ #include "display_draw.h" #include "flash.h" #include "model.h" +#include "mpu.h" -#ifdef FANCY_FATAL_ERROR -#include "rust_ui.h" -#endif +#ifdef KERNEL_MODE static secbool bootloader_locked_set = secfalse; static secbool bootloader_locked = secfalse; @@ -20,10 +19,15 @@ secbool secret_verify_header(void) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + bootloader_locked = memcmp(addr, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0 ? sectrue : secfalse; + + mpu_restore(mpu_mode); + bootloader_locked_set = sectrue; return bootloader_locked; } @@ -44,12 +48,14 @@ void secret_write_header(void) { } void secret_write(const uint8_t* data, uint32_t offset, uint32_t len) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); ensure(flash_unlock_write(), "secret write"); for (int i = 0; i < len; i++) { ensure(flash_area_write_byte(&SECRET_AREA, offset + i, data[i]), "secret write"); } ensure(flash_lock_write(), "secret write"); + mpu_restore(mpu_mode); } secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len) { @@ -63,28 +69,40 @@ secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); memcpy(data, addr, len); + mpu_restore(mpu_mode); return sectrue; } secbool secret_wiped(void) { uint32_t size = flash_area_get_size(&SECRET_AREA); + secbool wiped = sectrue; + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); for (int i = 0; i < size; i += 4) { uint32_t* addr = (uint32_t*)flash_area_get_address(&SECRET_AREA, i, 4); if (addr == NULL) { - return secfalse; + wiped = secfalse; + break; } if (*addr != 0xFFFFFFFF) { - return secfalse; + wiped = secfalse; + break; } } - return sectrue; + + mpu_restore(mpu_mode); + + return wiped; } void secret_erase(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); + mpu_restore(mpu_mode); } secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]) { @@ -114,3 +132,5 @@ void secret_prepare_fw(secbool allow_run_with_secret, secbool _trust_all) { } #endif } + +#endif // KERNEL_MODE diff --git a/core/embed/boardloader/startup_stm32f4.s b/core/embed/trezorhal/stm32f4/startup_stage_0.s similarity index 63% rename from core/embed/boardloader/startup_stm32f4.s rename to core/embed/trezorhal/stm32f4/startup_stage_0.s index 9533d932f93..b255baf3723 100644 --- a/core/embed/boardloader/startup_stm32f4.s +++ b/core/embed/trezorhal/stm32f4/startup_stage_0.s @@ -20,25 +20,21 @@ reset_handler: // wipe memory to remove any possible vestiges of sensitive data // use unpredictable value as a defense against side-channels - ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM mov r2, r4 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_0_start + ldr r1, =_startup_clear_ram_0_end bl memset_reg - - ldr r0, =sram_start // r0 - point to beginning of SRAM - ldr r1, =sram_end // r1 - point to byte after the end of SRAM - mov r2, r4 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_1_start + ldr r1, =_startup_clear_ram_1_end bl memset_reg // setup environment for subsequent stage of code - ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM - ldr r2, =0 // r2 - the word-sized value to be written + ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_0_start + ldr r1, =_startup_clear_ram_0_end bl memset_reg - - ldr r0, =sram_start // r0 - point to beginning of SRAM - ldr r1, =sram_end // r1 - point to byte after the end of SRAM - ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_1_start + ldr r1, =_startup_clear_ram_1_end bl memset_reg // copy data in from flash diff --git a/core/embed/bootloader/startup_stm32f4.s b/core/embed/trezorhal/stm32f4/startup_stage_1.s similarity index 70% rename from core/embed/bootloader/startup_stm32f4.s rename to core/embed/trezorhal/stm32f4/startup_stage_1.s index a1fb0c7e551..72a4cc8fab0 100644 --- a/core/embed/bootloader/startup_stm32f4.s +++ b/core/embed/trezorhal/stm32f4/startup_stage_1.s @@ -6,14 +6,12 @@ .type reset_handler, STT_FUNC reset_handler: // setup environment for subsequent stage of code - ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte where BOOT_ARGS region starts - ldr r2, =0 // r2 - the word-sized value to be written + ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_0_start + ldr r1, =_startup_clear_ram_0_end bl memset_reg - - ldr r0, =sram_start // r0 - point to beginning of SRAM - ldr r1, =sram_end // r1 - point to byte after the end of SRAM - ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_1_start + ldr r1, =_startup_clear_ram_1_end bl memset_reg // copy data in from flash @@ -35,7 +33,7 @@ reset_handler: // r11 contains the command passed to bootargs_set() // function called when the firmware rebooted to the bootloader - ldr r0, =g_boot_command_shadow + ldr r0, =g_boot_command_saved str r11, [r0] // enter the application code diff --git a/core/embed/bootloader_ci/startup_stm32f4.s b/core/embed/trezorhal/stm32f4/startup_stage_2.s similarity index 69% rename from core/embed/bootloader_ci/startup_stm32f4.s rename to core/embed/trezorhal/stm32f4/startup_stage_2.s index 59a80d3c183..e08f0de48c3 100644 --- a/core/embed/bootloader_ci/startup_stm32f4.s +++ b/core/embed/trezorhal/stm32f4/startup_stage_2.s @@ -6,14 +6,12 @@ .type reset_handler, STT_FUNC reset_handler: // setup environment for subsequent stage of code - ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte where BOOT_ARGS region starts - ldr r2, =0 // r2 - the word-sized value to be written + ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_0_start + ldr r1, =_startup_clear_ram_0_end bl memset_reg - - ldr r0, =sram_start // r0 - point to beginning of SRAM - ldr r1, =sram_end // r1 - point to byte after the end of SRAM - ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_1_start + ldr r1, =_startup_clear_ram_1_end bl memset_reg // copy data in from flash diff --git a/core/embed/trezorhal/stm32f4/startup_stage_4.s b/core/embed/trezorhal/stm32f4/startup_stage_4.s new file mode 100644 index 00000000000..d1a921abb34 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/startup_stage_4.s @@ -0,0 +1,37 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + + push {r0, r1} + + // setup the stack protector with provided random value + ldr r0, = __stack_chk_guard + str r2, [r0] + + ldr r0, =bss_start + ldr r1, =0 + ldr r2, =bss_end + sub r2, r2, r0 + bl memset + + // 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 + + pop {r0, r1} + + // enter the application code + // returns exit code in r0 + bl main + + // terminate the application + // pass exit code in r0 + b system_exit + + .end diff --git a/core/embed/trezorhal/stm32f4/supervise.c b/core/embed/trezorhal/stm32f4/supervise.c deleted file mode 100644 index 0ca4483062a..00000000000 --- a/core/embed/trezorhal/stm32f4/supervise.c +++ /dev/null @@ -1,118 +0,0 @@ -#include STM32_HAL_H - -#include - -#include "../mpu.h" -#include "common.h" -#include "display.h" -#include "supervise.h" - -#ifdef ARM_USER_MODE - -#ifdef STM32U5 -extern uint32_t g_boot_command; -__attribute__((noreturn)) static void _reboot_to_bootloader( - boot_command_t boot_command) { - g_boot_command = boot_command; - __disable_irq(); - delete_secrets(); - NVIC_SystemReset(); -} -#else -__attribute__((noreturn)) static void _reboot_to_bootloader( - boot_command_t boot_command) { - mpu_config_bootloader(); - jump_to_with_flag(IMAGE_CODE_ALIGN(BOOTLOADER_START + IMAGE_HEADER_SIZE), - boot_command); - for (;;) - ; -} -#endif - -void svc_reboot_to_bootloader(void) { - display_finish_actions(); - boot_command_t boot_command = bootargs_get_command(); - if (is_mode_unprivileged() && !is_mode_handler()) { - register uint32_t r0 __asm__("r0") = boot_command; - __asm__ __volatile__("svc %0" ::"i"(SVC_REBOOT_TO_BOOTLOADER), "r"(r0) - : "memory"); - } else { - ensure_compatible_settings(); - _reboot_to_bootloader(boot_command); - } -} - -void svc_reboot(void) { - if (is_mode_unprivileged() && !is_mode_handler()) { - __asm__ __volatile__("svc %0" ::"i"(SVC_REBOOT) : "memory"); - } else { - NVIC_SystemReset(); - } -} - -void SVC_C_Handler(uint32_t *stack) { - uint8_t svc_number = ((uint8_t *)stack[6])[-2]; - switch (svc_number) { - case SVC_ENABLE_IRQ: - HAL_NVIC_EnableIRQ(stack[0]); - break; - case SVC_DISABLE_IRQ: - HAL_NVIC_DisableIRQ(stack[0]); - break; - case SVC_SET_PRIORITY: - NVIC_SetPriority(stack[0], stack[1]); - break; -#ifdef SYSTEM_VIEW - case SVC_GET_DWT_CYCCNT: - cyccnt_cycles = *DWT_CYCCNT_ADDR; - break; -#endif - case SVC_SHUTDOWN: - shutdown_privileged(); - for (;;) - ; - break; - case SVC_REBOOT_TO_BOOTLOADER: - ensure_compatible_settings(); - - __asm__ volatile("msr control, %0" ::"r"(0x0)); - __asm__ volatile("isb"); - - // The input stack[0] argument comes from R0 saved when SVC was called - // from svc_reboot_to_bootloader. The __asm__ directive expects address as - // argument, hence the & in front of it, otherwise it would try - // to dereference the value and fault - __asm__ volatile( - "mov r0, %[boot_command]" ::[boot_command] "r"(&stack[0])); - - // See stack layout in - // https://developer.arm.com/documentation/ka004005/latest We are changing - // return address in PC to land into reboot to avoid any bug with ROP and - // raising privileges. - stack[6] = (uintptr_t)_reboot_to_bootloader; - return; - case SVC_GET_SYSTICK_VAL: - systick_val_copy = SysTick->VAL; - break; - case SVC_REBOOT: - NVIC_SystemReset(); - break; - default: - stack[0] = 0xffffffff; - break; - } -} - -__attribute__((naked)) void SVC_Handler(void) { - __asm volatile( - " tst lr, #4 \n" // Test Bit 3 to see which stack pointer we should - // use. - " ite eq \n" // Tell the assembler that the nest 2 instructions - // are if-then-else - " mrseq r0, msp \n" // Make R0 point to main stack pointer - " mrsne r0, psp \n" // Make R0 point to process stack pointer - " b SVC_C_Handler \n" // Off to C land - ); -} - -#endif // ARM_USER_MODE diff --git a/core/embed/trezorhal/stm32f4/supervise.h b/core/embed/trezorhal/stm32f4/supervise.h deleted file mode 100644 index 9affd8b770b..00000000000 --- a/core/embed/trezorhal/stm32f4/supervise.h +++ /dev/null @@ -1,84 +0,0 @@ -// supervisor call functions - -#define SVC_ENABLE_IRQ 0 -#define SVC_DISABLE_IRQ 1 -#define SVC_SET_PRIORITY 2 -#define SVC_SHUTDOWN 4 -#define SVC_REBOOT_TO_BOOTLOADER 5 -#define SVC_GET_SYSTICK_VAL 6 -#define SVC_REBOOT 7 - -#include -#include "boot_args.h" -#include "common.h" -#include "image.h" - -// from common.c -extern uint32_t systick_val_copy; - -// from util.s -extern void shutdown_privileged(void); -extern void ensure_compatible_settings(void); - -static inline uint32_t is_mode_unprivileged(void) { - uint32_t r0; - __asm__ volatile("mrs %0, control" : "=r"(r0)); - return r0 & 1; -} - -static inline uint32_t is_mode_handler(void) { - uint32_t r0; - __asm__ volatile("mrs %0, ipsr" : "=r"(r0)); - return (r0 & 0x1FF) != 0; -} - -static inline void svc_enableIRQ(uint32_t IRQn) { - if (is_mode_unprivileged() && !is_mode_handler()) { - register uint32_t r0 __asm__("r0") = IRQn; - __asm__ __volatile__("svc %0" ::"i"(SVC_ENABLE_IRQ), "r"(r0) : "memory"); - } else { - HAL_NVIC_EnableIRQ(IRQn); - } -} - -static inline void svc_disableIRQ(uint32_t IRQn) { - if (is_mode_unprivileged() && !is_mode_handler()) { - register uint32_t r0 __asm__("r0") = IRQn; - __asm__ __volatile__("svc %0" ::"i"(SVC_DISABLE_IRQ), "r"(r0) : "memory"); - } else { - HAL_NVIC_DisableIRQ(IRQn); - } -} - -static inline void svc_setpriority(uint32_t IRQn, uint32_t priority) { - if (is_mode_unprivileged() && !is_mode_handler()) { - register uint32_t r0 __asm__("r0") = IRQn; - register uint32_t r1 __asm__("r1") = priority; - __asm__ __volatile__("svc %0" ::"i"(SVC_SET_PRIORITY), "r"(r0), "r"(r1) - : "memory"); - } else { - NVIC_SetPriority(IRQn, priority); - } -} - -static inline void svc_shutdown(void) { - if (is_mode_unprivileged() && !is_mode_handler()) { - __asm__ __volatile__("svc %0" ::"i"(SVC_SHUTDOWN) : "memory"); - } else { - shutdown_privileged(); - } -} - -void svc_reboot_to_bootloader(void); - -void svc_reboot(void); - -static inline uint32_t svc_get_systick_val(void) { - if (is_mode_unprivileged() && !is_mode_handler()) { - __asm__ __volatile__("svc %0" ::"i"(SVC_GET_SYSTICK_VAL) : "memory"); - return systick_val_copy; - } else { - systick_val_copy = SysTick->VAL; - return systick_val_copy; - } -} diff --git a/core/embed/trezorhal/stm32f4/syscall.c b/core/embed/trezorhal/stm32f4/syscall.c new file mode 100644 index 00000000000..eadac852453 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/syscall.c @@ -0,0 +1,162 @@ +/* + * 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 "syscall.h" +#include "mpu.h" + +#ifdef SYSCALL_DISPATCH + +__attribute__((naked, no_stack_protector)) static uint32_t _invoke_app_callback( + uint32_t arg1, uint32_t arg2, uint32_t arg3, void *callback) { + __asm__ volatile( + "push {r1-r12, lr} \n" + +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + "mrs r12, PSPLIM \n" // Backup unprivileged stack limit + "push {r12} \n" +#endif + "mrs r12, PSP \n" // Backup unprivileged stack pointer + "push {r12} \n" + + "sub r12, r12, #32 \n" // Reserve space for stack frame + "msr PSP, r12 \n" + + "str r0, [r12, #0] \n" // pass r0 + "str r1, [r12, #4] \n" // pass r1 + "str r2, [r12, #8] \n" // pass r2 + + "mov r1, #0 \n" + + "mov r4, r1 \n" // Clear registers r4-r11 + "mov r5, r1 \n" + "mov r6, r1 \n" + "mov r7, r1 \n" + "mov r8, r1 \n" + "mov r9, r1 \n" + "mov r10, r1 \n" + "mov r11, r1 \n" + + "str r1, [r12, #12] \n" // clear r3 + "str r1, [r12, #16] \n" // clear r12 + "str r1, [r12, #20] \n" // clear lr + + "bic r3, r3, #1 \n" + "str r3, [r12, #24] \n" // return address + + "ldr r1, = 0x01000000 \n" + "str r1, [r12, #28] \n" // xPSR + + "vmov r0, s0 \n" // Use FPU instruction to ensure lazy + // stacking + + // return to Secure Thread mode (use Secure PSP) + "ldr lr, = 0xFFFFFFFD \n" + "bx lr \n"); +} + +uint32_t invoke_app_callback(uint32_t args1, uint32_t arg2, uint32_t arg3, + void *callback) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_APP); + uint32_t retval = _invoke_app_callback(args1, arg2, arg3, callback); + mpu_reconfig(mpu_mode); + return retval; +} + +__attribute__((naked, no_stack_protector)) void return_from_app_callback( + uint32_t retval, uint32_t *msp) { + __asm__ volatile( + "MSR MSP, R1 \n" + "POP {R1} \n" + "MSR PSP, R1 \n" +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + "POP {R1} \n" + "MSR PSPLIM, R1 \n" +#endif + + "LDR R1, = 0xE000EF34 \n" // FPU->FPCCR + "LDR R2, [R1] \n" + "BIC R2, R2, #1 \n" // Clear LSPACT to suppress repeated lazy + "STR R2, [R1] \n" // stacking that was already done + + "POP {R1-R12, LR} \n" + "BX LR \n"); +} + +__attribute__((naked, no_stack_protector)) static uint32_t _invoke_unpriv( + uint32_t stack_addr, uint32_t stack_lim, void *callback) { + __asm__ volatile( + "push {r1-r12, lr} \n" + +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + "mrs r12, PSPLIM \n" // Backup unprivileged stack limit + "push {r12} \n" +#endif + "mrs r12, PSP \n" // Backup unprivileged stack pointer + "push {r12} \n" + + "mov r12, r0 \n" // setup stack for unprivileged call inside + // kernel + "sub r12, r12, #32 \n" + "msr PSP, r12 \n" + "msr PSPLIM, r1 \n" + + "mov r3, #0 \n" + + "mov r4, r3 \n" // Clear registers r4-r11 + "mov r5, r3 \n" + "mov r6, r3 \n" + "mov r7, r3 \n" + "mov r8, r3 \n" + "mov r9, r3 \n" + "mov r10, r3 \n" + "mov r11, r3 \n" + + "str r3, [r12, #0] \n" // r0 + "str r3, [r12, #4] \n" // r1" + "str r3, [r12, #8] \n" // r2" + "str r3, [r12, #12] \n" // r3" + "str r3, [r12, #16] \n" // r12" + "str r3, [r12, #20] \n" // lr" + + "bic r3, r2, #1 \n" + "str r3, [r12, #24] \n" // return address + + "ldr r1, = 0x01000000 \n" + "str r1, [r12, #28] \n" // xPSR + + "vmov r0, s0 \n" // Use FPU instruction to ensure lazy + // stacking + + // return to Secure Thread mode (use Secure PSP) + "ldr lr, = 0xFFFFFFFD \n" + "bx lr \n"); +} + +extern const void _eustack; +extern const void _sustack; + +uint32_t invoke_unpriv(void *func) { + uint32_t *stack = (uint32_t *)&_eustack; + uint32_t *stack_lim = (uint32_t *)&_sustack; + + uint32_t retval = _invoke_unpriv((uint32_t)stack, (uint32_t)stack_lim, func); + return retval; +} + +#endif // SYSCALL_DISPATCH diff --git a/core/embed/trezorhal/stm32f4/syscall.h b/core/embed/trezorhal/stm32f4/syscall.h new file mode 100644 index 00000000000..944cd2981df --- /dev/null +++ b/core/embed/trezorhal/stm32f4/syscall.h @@ -0,0 +1,220 @@ +/* + * 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_SYSCALL_H +#define TREZORHAL_SYSCALL_H + +#include + +#include "applet.h" +#include "syscall_numbers.h" + +// Reserved SVC numbers +#define SVC_SYSCALL 0 +#define SVC_SYSTASK_YIELD 1 +#define SVC_CALLBACK_RETURN 2 + +#ifdef KERNEL_MODE + +// Handles all syscall requests. +// +// `args` points to an array of six 32-bit arguments. +// `syscall` is the syscall number, which is one of the `SYSCALL_XXX` constants. +// +// Input parameters are passed in `args[0]` to `args[5]`, +// and unused arguments may have undefined values. +// +// Return values must be copied to `args[0]` and +// `args[1]` (if returning a 64-bit value). +void syscall_handler(uint32_t* args, uint32_t syscall); + +// Invokes the application callback from the syscall handler. +// +// This is a *temporary* helper function used to invoke application callbacks +// from the syscall handler. It will be removed once all callback arguments +// are eliminated from syscalls. +uint32_t invoke_app_callback(uint32_t args1, uint32_t arg2, uint32_t arg3, + void* callback); + +// Internal function for returning from an application callback. +// This function is called from an unprivileged app via an SVC call. It restores +// the stack pointer and returns control to the privileged caller. +void return_from_app_callback(uint32_t retval, uint32_t* msp); + +// Invokes an unprivileged function from privileged mode. +// +// This is a *temporary* helper function used to control the STM32 SAES +// peripheral from unprivileged mode for backward compatibility (due to +// different hardware keys being used in privileged and unprivileged modes). +uint32_t invoke_unpriv(void* func); + +#else // KERNEL_MODE + +static inline uint32_t __attribute__((no_stack_protector)) +syscall_invoke0(uint32_t syscall) { + register uint32_t ret __asm__("r0"); + register uint32_t r6 __asm__("r6") = syscall; + + __asm__ volatile("svc %[svid]\n" + : "=r"(ret) + : [svid] "i"(SVC_SYSCALL), "r"(r6) + : "memory"); + + return ret; +} + +static inline uint64_t __attribute__((no_stack_protector)) +syscall_invoke0_ret64(uint32_t syscall) { + register uint32_t ret_lo __asm__("r0"); + register uint32_t ret_hi __asm__("r1"); + register uint32_t r6 __asm__("r6") = syscall; + + __asm__ volatile("svc %[svid]\n" + : "=r"(ret_lo), "=r"(ret_hi) + : [svid] "i"(SVC_SYSCALL), "r"(r6) + : "memory"); + + return ((uint64_t)ret_hi << 32) | ret_lo; +} + +static inline uint32_t __attribute__((no_stack_protector)) +syscall_invoke1(uint32_t arg1, uint32_t syscall) { + register uint32_t ret __asm__("r0") = arg1; + register uint32_t r6 __asm__("r6") = syscall; + + __asm__ volatile("svc %[svid]\n" + : "=r"(ret) + : [svid] "i"(SVC_SYSCALL), "r"(ret), "r"(r6) + : "memory"); + return ret; +} + +static inline uint32_t __attribute__((no_stack_protector)) +syscall_invoke2(uint32_t arg1, uint32_t arg2, uint32_t syscall) { + register uint32_t ret __asm__("r0") = arg1; + register uint32_t r1 __asm__("r1") = arg2; + register uint32_t r6 __asm__("r6") = syscall; + + __asm__ volatile("svc %[svid]\n" + : "=r"(ret) + : [svid] "i"(SVC_SYSCALL), "r"(ret), "r"(r1), "r"(r6) + : "memory"); + + return ret; +} + +static inline uint64_t __attribute__((no_stack_protector)) +syscall_invoke2_ret64(uint32_t arg1, uint32_t arg2, uint32_t syscall) { + register uint32_t ret_lo __asm__("r0") = arg1; + register uint32_t ret_hi __asm__("r1") = arg2; + register uint32_t r6 __asm__("r6") = syscall; + + __asm__ volatile("svc %[svid]\n" + : "=r"(ret_lo), "=r"(ret_hi) + : [svid] "i"(SVC_SYSCALL), "r"(ret_lo), "r"(ret_hi), "r"(r6) + : "memory"); + + return ((uint64_t)ret_hi << 32) | ret_lo; +} + +static inline uint32_t __attribute__((no_stack_protector)) +syscall_invoke3(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t syscall) { + register uint32_t ret __asm__("r0") = arg1; + register uint32_t r1 __asm__("r1") = arg2; + register uint32_t r2 __asm__("r2") = arg3; + register uint32_t r6 __asm__("r6") = syscall; + + __asm__ volatile("svc %[svid]\n" + : "=r"(ret) + : [svid] "i"(SVC_SYSCALL), "r"(ret), "r"(r1), "r"(r2), + "r"(r6) + : "memory"); + + return ret; +} + +static inline uint32_t __attribute__((no_stack_protector)) +syscall_invoke4(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, + uint32_t syscall) { + register uint32_t ret __asm__("r0") = arg1; + register uint32_t r1 __asm__("r1") = arg2; + register uint32_t r2 __asm__("r2") = arg3; + register uint32_t r3 __asm__("r3") = arg4; + register uint32_t r6 __asm__("r6") = syscall; + + __asm__ volatile("svc %[svid]\n" + : "=r"(ret) + : [svid] "i"(SVC_SYSCALL), "r"(ret), "r"(r1), "r"(r2), + "r"(r3), "r"(r6) + : "memory"); + + return ret; +} + +static inline uint32_t __attribute__((no_stack_protector)) +syscall_invoke5(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, + uint32_t arg5, uint32_t syscall) { + register uint32_t ret __asm__("r0") = arg1; + register uint32_t r1 __asm__("r1") = arg2; + register uint32_t r2 __asm__("r2") = arg3; + register uint32_t r3 __asm__("r3") = arg4; + register uint32_t r4 __asm__("r4") = arg5; + register uint32_t r6 __asm__("r6") = syscall; + + __asm__ volatile("svc %[svid]\n" + : "=r"(ret) + : [svid] "i"(SVC_SYSCALL), "r"(ret), "r"(r1), "r"(r2), + "r"(r3), "r"(r4), "r"(r6) + : "memory"); + + return ret; +} + +static inline uint32_t __attribute__((no_stack_protector)) +syscall_invoke6(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, + uint32_t arg5, uint32_t arg6, uint32_t syscall) { + register uint32_t ret __asm__("r0") = arg1; + register uint32_t r1 __asm__("r1") = arg2; + register uint32_t r2 __asm__("r2") = arg3; + register uint32_t r3 __asm__("r3") = arg4; + register uint32_t r4 __asm__("r4") = arg5; + register uint32_t r5 __asm__("r5") = arg6; + register uint32_t r6 __asm__("r6") = syscall; + + __asm__ volatile("svc %[svid]\n" + : "=r"(ret) + : [svid] "i"(SVC_SYSCALL), "r"(ret), "r"(r1), "r"(r2), + "r"(r3), "r"(r4), "r"(r5), "r"(r6) + : "memory"); + + return ret; +} + +#endif // KERNEL_MODE + +static inline void __attribute__((no_stack_protector)) +syscall_return_from_callback(uint32_t retval) { + register uint32_t r0 __asm__("r0") = retval; + __asm__ volatile("svc %[svid]\n" + : + : [svid] "i"(SVC_CALLBACK_RETURN), "r"(r0) + : "memory"); +} + +#endif // TREZORHAL_SYSCALL_H diff --git a/core/embed/trezorhal/stm32f4/syscall_dispatch.c b/core/embed/trezorhal/stm32f4/syscall_dispatch.c new file mode 100644 index 00000000000..6993c2ce418 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/syscall_dispatch.c @@ -0,0 +1,528 @@ +/* + * 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 TREZOR_BOARD + +#include "syscall.h" + +#include "bootutils.h" +#include "button.h" +#include "display.h" +#include "entropy.h" +#include "fwutils.h" +#include "haptic.h" +#include "hash_processor.h" +#include "irq.h" +#include "mpu.h" +#include "optiga.h" +#include "rng.h" +#include "sdcard.h" +#include "secret.h" +#include "systask.h" +#include "system.h" +#include "systick.h" +#include "touch.h" +#include "translations.h" +#include "unit_variant.h" +#include "usb.h" +#include "usb_hid.h" +#include "usb_vcp.h" +#include "usb_webusb.h" + +#ifdef SYSCALL_DISPATCH + +static PIN_UI_WAIT_CALLBACK storage_init_callback = NULL; + +static secbool storage_init_callback_wrapper( + uint32_t wait, uint32_t progress, enum storage_ui_message_t message) { + return (secbool)invoke_app_callback(wait, progress, message, + storage_init_callback); +} + +static firmware_hash_callback_t firmware_hash_callback = NULL; + +static void firmware_hash_callback_wrapper(void *context, uint32_t progress, + uint32_t total) { + invoke_app_callback((uint32_t)context, progress, total, + firmware_hash_callback); +} + +__attribute((no_stack_protector)) void syscall_handler(uint32_t *args, + uint32_t syscall) { + switch (syscall) { + case SYSCALL_SYSTEM_EXIT: { + systask_t *task = systask_active(); + systask_exit(task, (int)args[0]); + } break; + case SYSCALL_SYSTEM_EXIT_ERROR: { + systask_t *task = systask_active(); + systask_exit_error(task, (const char *)args[0], (const char *)args[1], + (const char *)args[2]); + } break; + case SYSCALL_SYSTEM_EXIT_FATAL: { + systask_t *task = systask_active(); + systask_exit_fatal(task, (const char *)args[0], (const char *)args[1], + (int)args[2]); + } break; + case SYSCALL_SYSTICK_CYCLES: { + uint64_t cycles = systick_cycles(); + args[0] = cycles & 0xFFFFFFFF; + args[1] = cycles >> 32; + } break; + + case SYSCALL_SYSTICK_US: { + uint64_t cycles = systick_us(); + args[0] = cycles & 0xFFFFFFFF; + args[1] = cycles >> 32; + } break; + + case SYSCALL_SYSTICK_MS: + args[0] = systick_ms(); + break; + + case SYSCALL_SYSTICK_US_TO_CYCLES: { + uint64_t us = args[0] + ((uint64_t)args[1] << 32); + uint64_t cycles = systick_us_to_cycles(us); + args[0] = cycles & 0xFFFFFFFF; + args[1] = cycles >> 32; + } break; + + case SYSCALL_SECURE_SHUTDOWN: + secure_shutdown(); + break; + case SYSCALL_REBOOT: + reboot(); + break; + case SYSCALL_REBOOT_TO_BOOTLOADER: + reboot_to_bootloader(); + break; + case SYSCALL_REBOOT_AND_UPGRADE: + reboot_and_upgrade((uint8_t *)args[0]); + break; + +#ifdef STM32U5 + case SYSCALL_SHA256_INIT: { + hash_sha265_context_t *ctx = (hash_sha265_context_t *)args[0]; + hash_processor_sha256_init(ctx); + } break; + case SYSCALL_SHA256_UPDATE: { + hash_sha265_context_t *ctx = (hash_sha265_context_t *)args[0]; + const uint8_t *data = (const uint8_t *)args[1]; + uint32_t len = args[2]; + hash_processor_sha256_update(ctx, data, len); + } break; + case SYSCALL_SHA256_FINAL: { + hash_sha265_context_t *ctx = (hash_sha265_context_t *)args[0]; + uint8_t *output = (uint8_t *)args[1]; + hash_processor_sha256_final(ctx, output); + } break; + case SYSCALL_SHA256_CALC: { + const uint8_t *data = (const uint8_t *)args[0]; + uint32_t len = args[1]; + uint8_t *hash = (uint8_t *)args[2]; + hash_processor_sha256_calc(data, len, hash); + } break; +#endif // STM32U5 + + case SYSCALL_DISPLAY_SET_BACKLIGHT: { + args[0] = display_set_backlight((int)args[0]); + } break; + case SYSCALL_DISPLAY_GET_BACKLIGHT: { + args[0] = display_get_backlight(); + } break; + case SYSCALL_DISPLAY_SET_ORIENTATION: { + args[0] = display_set_orientation((int)args[0]); + } break; + case SYSCALL_DISPLAY_GET_ORIENTATION: { + args[0] = display_get_orientation(); + + } break; +#if XFRAMEBUFFER + case SYSCALL_DISPLAY_GET_FB_INFO: { + display_fb_info_t *info = (display_fb_info_t *)args[0]; + *info = display_get_frame_buffer(); + } break; +#else + case SYSCALL_DISPLAY_WAIT_FOR_SYNC: { + display_wait_for_sync(); + } break; +#endif + case SYSCALL_DISPLAY_FILL: { + const gfx_bitblt_t *bb = (const gfx_bitblt_t *)args[0]; + display_fill(bb); + } break; +#ifdef USE_RGB_COLORS + case SYSCALL_DISPLAY_COPY_RGB565: { + const gfx_bitblt_t *bb = (const gfx_bitblt_t *)args[0]; + display_copy_rgb565(bb); + } break; +#endif + case SYSCALL_DISPLAY_REFRESH: { + display_refresh(); + } break; + case SYSCALL_USB_INIT: { + const usb_dev_info_t *dev_info = (const usb_dev_info_t *)args[0]; + args[0] = usb_init(dev_info); + } break; + case SYSCALL_USB_DEINIT: { + usb_deinit(); + } break; + case SYSCALL_USB_START: { + args[0] = usb_start(); + } break; + case SYSCALL_USB_STOP: { + usb_stop(); + } break; + case SYSCALL_USB_CONFIGURED: { + args[0] = usb_configured(); + } break; + case SYSCALL_USB_HID_ADD: { + args[0] = usb_hid_add((const usb_hid_info_t *)args[0]); + } break; + case SYSCALL_USB_HID_CAN_READ: { + args[0] = usb_hid_can_read((uint8_t)args[0]); + } break; + case SYSCALL_USB_HID_CAN_WRITE: { + args[0] = usb_hid_can_write((uint8_t)args[0]); + } break; + case SYSCALL_USB_HID_READ: { + args[0] = usb_hid_read((uint8_t)args[0], (uint8_t *)args[1], args[2]); + } break; + case SYSCALL_USB_HID_WRITE: { + args[0] = + usb_hid_write((uint8_t)args[0], (const uint8_t *)args[1], args[2]); + } break; + case SYSCALL_USB_HID_READ_SELECT: { + args[0] = usb_hid_read_select((uint32_t)args[0]); + } break; + case SYSCALL_USB_HID_READ_BLOCKING: { + args[0] = usb_hid_read_blocking((uint8_t)args[0], (uint8_t *)args[1], + args[2], (int)args[3]); + } break; + case SYSCALL_USB_HID_WRITE_BLOCKING: { + args[0] = usb_hid_write_blocking( + (uint8_t)args[0], (const uint8_t *)args[1], args[2], (int)args[3]); + } break; + case SYSCALL_USB_VCP_ADD: { + args[0] = usb_vcp_add((const usb_vcp_info_t *)args[0]); + } break; + case SYSCALL_USB_VCP_CAN_READ: { + args[0] = usb_vcp_can_read((uint8_t)args[0]); + } break; + case SYSCALL_USB_VCP_CAN_WRITE: { + args[0] = usb_vcp_can_write((uint8_t)args[0]); + } break; + case SYSCALL_USB_VCP_READ: { + args[0] = usb_vcp_read((uint8_t)args[0], (uint8_t *)args[1], args[2]); + } break; + case SYSCALL_USB_VCP_WRITE: { + args[0] = + usb_vcp_write((uint8_t)args[0], (const uint8_t *)args[1], args[2]); + } break; + case SYSCALL_USB_VCP_READ_BLOCKING: { + args[0] = usb_vcp_read_blocking((uint8_t)args[0], (uint8_t *)args[1], + args[2], (int)args[3]); + } break; + case SYSCALL_USB_VCP_WRITE_BLOCKING: { + args[0] = usb_vcp_write_blocking( + (uint8_t)args[0], (const uint8_t *)args[1], args[2], (int)args[3]); + } break; + case SYSCALL_USB_WEBUSB_ADD: { + args[0] = usb_webusb_add((const usb_webusb_info_t *)args[0]); + } break; + case SYSCALL_USB_WEBUSB_CAN_READ: { + args[0] = usb_webusb_can_read((uint8_t)args[0]); + } break; + case SYSCALL_USB_WEBUSB_CAN_WRITE: { + args[0] = usb_webusb_can_write((uint8_t)args[0]); + } break; + case SYSCALL_USB_WEBUSB_READ: { + args[0] = usb_webusb_read((uint8_t)args[0], (uint8_t *)args[1], args[2]); + } break; + case SYSCALL_USB_WEBUSB_WRITE: { + args[0] = + usb_webusb_write((uint8_t)args[0], (const uint8_t *)args[1], args[2]); + } break; + case SYSCALL_USB_WEBUSB_READ_SELECT: { + args[0] = usb_webusb_read_select((uint32_t)args[0]); + } break; + case SYSCALL_USB_WEBUSB_READ_BLOCKING: { + args[0] = usb_webusb_read_blocking((uint8_t)args[0], (uint8_t *)args[1], + args[2], (int)args[3]); + } break; + case SYSCALL_USB_WEBUSB_WRITE_BLOCKING: { + args[0] = usb_webusb_write_blocking( + (uint8_t)args[0], (const uint8_t *)args[1], args[2], (int)args[3]); + } break; +#ifdef USE_SD_CARD + case SYSCALL_SDCARD_POWER_ON: { + args[0] = sdcard_power_on(); + } break; + case SYSCALL_SDCARD_POWER_OFF: { + sdcard_power_off(); + } break; + case SYSCALL_SDCARD_IS_PRESENT: { + args[0] = sdcard_is_present(); + } break; + case SYSCALL_SDCARD_GET_CAPACITY: { + args[0] = sdcard_get_capacity_in_bytes(); + } break; + case SYSCALL_SDCARD_READ_BLOCKS: { + args[0] = sdcard_read_blocks((uint32_t *)args[0], args[1], args[2]); + } break; + case SYSCALL_SDCARD_WRITE_BLOCKS: { + args[0] = + sdcard_write_blocks((const uint32_t *)args[0], args[1], args[2]); + } break; +#endif + + case SYSCALL_UNIT_VARIANT_PRESENT: { + args[0] = unit_variant_present(); + } break; + case SYSCALL_UNIT_VARIANT_GET_COLOR: { + args[0] = unit_variant_get_color(); + } break; + case SYSCALL_UNIT_VARIANT_GET_PACKAGING: { + args[0] = unit_variant_get_packaging(); + } break; + case SYSCALL_UNIT_VARIANT_GET_BTCONLY: { + args[0] = unit_variant_get_btconly(); + } break; + case SYSCALL_UNIT_VARIANT_IS_SD_HOTSWAP_ENABLED: { + args[0] = unit_variant_is_sd_hotswap_enabled(); + } break; + case SYSCALL_SECRET_BOOTLOADER_LOCKED: { + args[0] = secret_bootloader_locked(); + } break; +#ifdef USE_BUTTON + case SYSCALL_BUTTON_READ: { + args[0] = button_read(); + } break; + case SYSCALL_BUTTON_STATE_LEFT: { + args[0] = button_state_left(); + } break; + case SYSCALL_BUTTON_STATE_RIGHT: { + args[0] = button_state_right(); + } break; +#endif +#ifdef USE_TOUCH + case SYSCALL_TOUCH_GET_EVENT: { + args[0] = touch_get_event(); + } break; +#endif +#ifdef USE_HAPTIC + case SYSCALL_HAPTIC_SET_ENABLED: { + haptic_set_enabled(args[0]); + } break; + case SYSCALL_HAPTIC_GET_ENABLED: { + args[0] = haptic_get_enabled(); + } break; + case SYSCALL_HAPTIC_TEST: { + args[0] = haptic_test(args[0]); + } break; + case SYSCALL_HAPTIC_PLAY: { + args[0] = haptic_play(args[0]); + } break; + case SYSCALL_HAPTIC_PLAY_CUSTOM: { + args[0] = haptic_play_custom(args[0], args[1]); + } break; +#endif + +#ifdef USE_OPTIGA + /*optiga_sign_result optiga_sign(uint8_t index, const uint8_t *digest, + size_t digest_size, uint8_t + *signature, size_t max_sig_size, size_t *sig_size); + + */ + case SYSCALL_OPTIGA_CERT_SIZE: { + uint8_t index = args[0]; + size_t *cert_size = (size_t *)args[1]; + args[0] = optiga_cert_size(index, cert_size); + } break; + case SYSCALL_OPTIGA_READ_CERT: { + uint8_t index = args[0]; + uint8_t *cert = (uint8_t *)args[1]; + size_t max_cert_size = args[2]; + size_t *cert_size = (size_t *)args[3]; + args[0] = optiga_read_cert(index, cert, max_cert_size, cert_size); + } break; + case SYSCALL_OPTIGA_READ_SEC: { + uint8_t *sec = (uint8_t *)args[0]; + args[0] = optiga_read_sec(sec); + } break; + case SYSCALL_OPTIGA_RANDOM_BUFFER: { + uint8_t *dest = (uint8_t *)args[0]; + size_t size = args[1]; + args[0] = optiga_random_buffer(dest, size); + } break; +#if PYOPT == 0 + case SYSCALL_OPTIGA_SET_SEC_MAX: { + optiga_set_sec_max(); + } break; +#endif +#endif + case SYSCALL_STORAGE_INIT: { + storage_init_callback = (PIN_UI_WAIT_CALLBACK)args[0]; + const uint8_t *salt = (const uint8_t *)args[1]; + uint16_t salt_len = args[2]; + mpu_reconfig(MPU_MODE_STORAGE); + storage_init(storage_init_callback_wrapper, salt, salt_len); + } break; + case SYSCALL_STORAGE_WIPE: { + mpu_reconfig(MPU_MODE_STORAGE); + storage_wipe(); + } break; + case SYSCALL_STORAGE_IS_UNLOCKED: { + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_is_unlocked(); + } break; + case SYSCALL_STORAGE_LOCK: { + mpu_reconfig(MPU_MODE_STORAGE); + storage_lock(); + } break; + case SYSCALL_STORAGE_UNLOCK: { + const uint8_t *pin = (const uint8_t *)args[0]; + size_t pin_len = args[1]; + const uint8_t *ext_salt = (const uint8_t *)args[2]; + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_unlock(pin, pin_len, ext_salt); + } break; + case SYSCALL_STORAGE_HAS_PIN: { + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_has_pin(); + } break; + case SYSCALL_STORAGE_PIN_FAILS_INCREASE: { + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_pin_fails_increase(); + } break; + case SYSCALL_STORAGE_GET_PIN_REM: { + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_get_pin_rem(); + } break; + case SYSCALL_STORAGE_CHANGE_PIN: { + const uint8_t *oldpin = (const uint8_t *)args[0]; + size_t oldpin_len = args[1]; + const uint8_t *newpin = (const uint8_t *)args[2]; + size_t newpin_len = args[3]; + const uint8_t *old_ext_salt = (const uint8_t *)args[4]; + const uint8_t *new_ext_salt = (const uint8_t *)args[5]; + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_change_pin(oldpin, oldpin_len, newpin, newpin_len, + old_ext_salt, new_ext_salt); + } break; + case SYSCALL_STORAGE_ENSURE_NOT_WIPE_CODE: { + const uint8_t *pin = (const uint8_t *)args[0]; + size_t pin_len = args[1]; + mpu_reconfig(MPU_MODE_STORAGE); + storage_ensure_not_wipe_code(pin, pin_len); + } break; + case SYSCALL_STORAGE_HAS_WIPE_CODE: { + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_has_wipe_code(); + } break; + case SYSCALL_STORAGE_CHANGE_WIPE_CODE: { + const uint8_t *pin = (const uint8_t *)args[0]; + size_t pin_len = args[1]; + const uint8_t *ext_salt = (const uint8_t *)args[2]; + const uint8_t *wipe_code = (const uint8_t *)args[3]; + size_t wipe_code_len = args[4]; + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_change_wipe_code(pin, pin_len, ext_salt, wipe_code, + wipe_code_len); + } break; + case SYSCALL_STORAGE_HAS: { + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_has((uint16_t)args[0]); + } break; + + case SYSCALL_STORAGE_GET: { + uint16_t key = (uint16_t)args[0]; + void *val = (void *)args[1]; + uint16_t max_len = (uint16_t)args[2]; + uint16_t *len = (uint16_t *)args[3]; + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_get(key, val, max_len, len); + } break; + case SYSCALL_STORAGE_SET: { + uint16_t key = (uint16_t)args[0]; + const void *val = (const void *)args[1]; + uint16_t len = (uint16_t)args[2]; + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_set(key, val, len); + } break; + case SYSCALL_STORAGE_DELETE: { + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_delete((uint16_t)args[0]); + } break; + case SYSCALL_STORAGE_SET_COUNTER: { + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_set_counter((uint16_t)args[0], args[1]); + } break; + case SYSCALL_STORAGE_NEXT_COUNTER: { + mpu_reconfig(MPU_MODE_STORAGE); + args[0] = storage_next_counter((uint16_t)args[0], (uint32_t *)args[1]); + } break; + case SYSCALL_ENTROPY_GET: { + uint8_t *buf = (uint8_t *)args[0]; + entropy_get(buf); + } break; + case SYSCALL_TRANSLATIONS_WRITE: { + const uint8_t *data = (const uint8_t *)args[0]; + uint32_t offset = args[1]; + uint32_t len = args[2]; + args[0] = translations_write(data, offset, len); + } break; + case SYSCALL_TRANSLATIONS_READ: { + uint32_t *len = (uint32_t *)args[0]; + uint32_t offset = args[1]; + args[0] = (uint32_t)translations_read(len, offset); + } break; + case SYSCALL_TRANSLATIONS_ERASE: { + translations_erase(); + } break; + case SYSCALL_TRANSLATIONS_AREA_BYTESIZE: { + args[0] = translations_area_bytesize(); + } break; + case SYSCALL_RNG_GET: { + args[0] = rng_get(); + } break; + case SYSCALL_FIRMWARE_GET_VENDOR: { + args[0] = firmware_get_vendor((char *)args[0], args[1]); + } break; + case SYSCALL_FIRMWARE_CALC_HASH: { + const uint8_t *challenge = (const uint8_t *)args[0]; + size_t challenge_len = args[1]; + uint8_t *hash = (uint8_t *)args[2]; + size_t hash_len = args[3]; + firmware_hash_callback = (firmware_hash_callback_t)args[4]; + void *callback_context = (void *)args[5]; + + args[0] = + firmware_calc_hash(challenge, challenge_len, hash, hash_len, + firmware_hash_callback_wrapper, callback_context); + } break; + default: + args[0] = 0xffffffff; + break; + } +} + +#endif // SYSCALL_DISPATCH diff --git a/core/embed/trezorhal/stm32f4/syscall_numbers.h b/core/embed/trezorhal/stm32f4/syscall_numbers.h new file mode 100644 index 00000000000..2341d02ed7a --- /dev/null +++ b/core/embed/trezorhal/stm32f4/syscall_numbers.h @@ -0,0 +1,152 @@ +/* + * 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 SYSCALL_NUMBERS_H +#define SYSCALL_NUMBERS_H + +// Syscall identifiers +typedef enum { + + SYSCALL_SYSTEM_EXIT = 1, + SYSCALL_SYSTEM_EXIT_ERROR, + SYSCALL_SYSTEM_EXIT_FATAL, + + SYSCALL_SYSTICK_CYCLES, + SYSCALL_SYSTICK_MS, + SYSCALL_SYSTICK_US, + SYSCALL_SYSTICK_US_TO_CYCLES, + + SYSCALL_SECURE_SHUTDOWN, + SYSCALL_REBOOT, + SYSCALL_REBOOT_TO_BOOTLOADER, + SYSCALL_REBOOT_AND_UPGRADE, + + SYSCALL_SHA256_INIT, + SYSCALL_SHA256_UPDATE, + SYSCALL_SHA256_FINAL, + SYSCALL_SHA256_CALC, + + SYSCALL_DISPLAY_SET_BACKLIGHT, + SYSCALL_DISPLAY_GET_BACKLIGHT, + SYSCALL_DISPLAY_SET_ORIENTATION, + SYSCALL_DISPLAY_GET_ORIENTATION, + SYSCALL_DISPLAY_GET_FB_INFO, + SYSCALL_DISPLAY_WAIT_FOR_SYNC, + SYSCALL_DISPLAY_REFRESH, + SYSCALL_DISPLAY_FILL, + SYSCALL_DISPLAY_COPY_RGB565, + + SYSCALL_USB_INIT, + SYSCALL_USB_DEINIT, + SYSCALL_USB_START, + SYSCALL_USB_STOP, + SYSCALL_USB_CONFIGURED, + + SYSCALL_USB_HID_ADD, + SYSCALL_USB_HID_CAN_READ, + SYSCALL_USB_HID_CAN_WRITE, + SYSCALL_USB_HID_READ, + SYSCALL_USB_HID_WRITE, + SYSCALL_USB_HID_READ_SELECT, + SYSCALL_USB_HID_READ_BLOCKING, + SYSCALL_USB_HID_WRITE_BLOCKING, + SYSCALL_USB_VCP_ADD, + SYSCALL_USB_VCP_CAN_READ, + SYSCALL_USB_VCP_CAN_WRITE, + SYSCALL_USB_VCP_READ, + SYSCALL_USB_VCP_WRITE, + SYSCALL_USB_VCP_READ_BLOCKING, + SYSCALL_USB_VCP_WRITE_BLOCKING, + SYSCALL_USB_WEBUSB_ADD, + SYSCALL_USB_WEBUSB_CAN_READ, + SYSCALL_USB_WEBUSB_CAN_WRITE, + SYSCALL_USB_WEBUSB_READ, + SYSCALL_USB_WEBUSB_WRITE, + SYSCALL_USB_WEBUSB_READ_SELECT, + SYSCALL_USB_WEBUSB_READ_BLOCKING, + SYSCALL_USB_WEBUSB_WRITE_BLOCKING, + + SYSCALL_SDCARD_POWER_ON, + SYSCALL_SDCARD_POWER_OFF, + SYSCALL_SDCARD_IS_PRESENT, + SYSCALL_SDCARD_GET_CAPACITY, + SYSCALL_SDCARD_READ_BLOCKS, + SYSCALL_SDCARD_WRITE_BLOCKS, + + SYSCALL_UNIT_VARIANT_PRESENT, + SYSCALL_UNIT_VARIANT_GET_COLOR, + SYSCALL_UNIT_VARIANT_GET_PACKAGING, + SYSCALL_UNIT_VARIANT_GET_BTCONLY, + SYSCALL_UNIT_VARIANT_IS_SD_HOTSWAP_ENABLED, + + SYSCALL_SECRET_BOOTLOADER_LOCKED, + + SYSCALL_BUTTON_READ, + SYSCALL_BUTTON_STATE_LEFT, + SYSCALL_BUTTON_STATE_RIGHT, + + SYSCALL_TOUCH_GET_EVENT, + + SYSCALL_HAPTIC_SET_ENABLED, + SYSCALL_HAPTIC_GET_ENABLED, + SYSCALL_HAPTIC_TEST, + SYSCALL_HAPTIC_PLAY, + SYSCALL_HAPTIC_PLAY_CUSTOM, + + SYSCALL_OPTIGA_SIGN, + SYSCALL_OPTIGA_CERT_SIZE, + SYSCALL_OPTIGA_READ_CERT, + SYSCALL_OPTIGA_READ_SEC, + SYSCALL_OPTIGA_RANDOM_BUFFER, + SYSCALL_OPTIGA_SET_SEC_MAX, + + SYSCALL_STORAGE_INIT, + SYSCALL_STORAGE_WIPE, + SYSCALL_STORAGE_IS_UNLOCKED, + SYSCALL_STORAGE_LOCK, + SYSCALL_STORAGE_UNLOCK, + SYSCALL_STORAGE_HAS_PIN, + SYSCALL_STORAGE_PIN_FAILS_INCREASE, + SYSCALL_STORAGE_GET_PIN_REM, + SYSCALL_STORAGE_CHANGE_PIN, + SYSCALL_STORAGE_ENSURE_NOT_WIPE_CODE, + SYSCALL_STORAGE_HAS_WIPE_CODE, + SYSCALL_STORAGE_CHANGE_WIPE_CODE, + SYSCALL_STORAGE_HAS, + SYSCALL_STORAGE_GET, + SYSCALL_STORAGE_SET, + SYSCALL_STORAGE_DELETE, + SYSCALL_STORAGE_SET_COUNTER, + SYSCALL_STORAGE_NEXT_COUNTER, + + SYSCALL_ENTROPY_GET, + + SYSCALL_TRANSLATIONS_WRITE, + SYSCALL_TRANSLATIONS_READ, + SYSCALL_TRANSLATIONS_ERASE, + SYSCALL_TRANSLATIONS_AREA_BYTESIZE, + + SYSCALL_RNG_GET, + + SYSCALL_FIRMWARE_GET_VENDOR, + SYSCALL_FIRMWARE_CALC_HASH, + +} syscall_number_t; + +#endif // SYSCALL_NUMBERS_H diff --git a/core/embed/trezorhal/stm32f4/syscall_stubs.c b/core/embed/trezorhal/stm32f4/syscall_stubs.c new file mode 100644 index 00000000000..91f706d4343 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/syscall_stubs.c @@ -0,0 +1,652 @@ +/* + * 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 "syscall.h" + +#ifndef KERNEL_MODE + +// ============================================================================= +// system.h +// ============================================================================= + +#include "system.h" + +void system_exit(int exit_code) { + syscall_invoke1(exit_code, SYSCALL_SYSTEM_EXIT); + while (1) + ; +} + +void system_exit_error(const char *title, const char *message, + const char *footer) { + syscall_invoke3((uint32_t)title, (uint32_t)message, (uint32_t)footer, + SYSCALL_SYSTEM_EXIT_ERROR); + while (1) + ; +} + +void system_exit_fatal(const char *message, const char *file, int line) { + syscall_invoke3((uint32_t)message, (uint32_t)file, line, + SYSCALL_SYSTEM_EXIT_FATAL); + while (1) + ; +} + +// ============================================================================= +// systick.h +// ============================================================================= + +#include "systick.h" + +uint64_t __attribute__((no_stack_protector)) systick_cycles(void) { + return syscall_invoke0_ret64(SYSCALL_SYSTICK_CYCLES); +} + +uint64_t systick_us(void) { return syscall_invoke0_ret64(SYSCALL_SYSTICK_US); } + +uint32_t systick_ms(void) { return syscall_invoke0(SYSCALL_SYSTICK_MS); } + +uint64_t systick_us_to_cycles(uint64_t us) { + uint32_t arg0 = us & 0xFFFFFFFF; + uint32_t arg1 = us >> 32; + return syscall_invoke2_ret64(arg0, arg1, SYSCALL_SYSTICK_US_TO_CYCLES); +} + +// ============================================================================= +// bootutils.h +// ============================================================================= + +#include "bootutils.h" + +void secure_shutdown(void) { + syscall_invoke0(SYSCALL_SECURE_SHUTDOWN); + while (1) + ; +} + +void reboot_to_bootloader(void) { + syscall_invoke0(SYSCALL_REBOOT_TO_BOOTLOADER); + while (1) + ; +} + +void reboot_and_upgrade(const uint8_t hash[32]) { + syscall_invoke1(SYSCALL_REBOOT_AND_UPGRADE, (uint32_t)hash); + while (1) + ; +} + +void reboot(void) { + syscall_invoke0(SYSCALL_REBOOT); + while (1) + ; +} + +// ============================================================================= +// hash_processor.h +// ============================================================================= + +#include "hash_processor.h" + +void hash_processor_sha256_init(hash_sha265_context_t *ctx) { + syscall_invoke1((uint32_t)ctx, SYSCALL_SHA256_INIT); +} + +// Feed the hash next chunk of data +void hash_processor_sha256_update(hash_sha265_context_t *ctx, + const uint8_t *data, uint32_t len) { + syscall_invoke3((uint32_t)ctx, (uint32_t)data, len, SYSCALL_SHA256_UPDATE); +} + +// Finalize the hash calculation, retrieve the digest +void hash_processor_sha256_final(hash_sha265_context_t *ctx, uint8_t *output) { + syscall_invoke2((uint32_t)ctx, (uint32_t)output, SYSCALL_SHA256_FINAL); +} + +void hash_processor_sha256_calc(const uint8_t *data, uint32_t len, + uint8_t *hash) { + syscall_invoke3((uint32_t)data, len, (uint32_t)hash, SYSCALL_SHA256_CALC); +} + +// ============================================================================= +// xdisplay.h +// ============================================================================= + +#include "display.h" + +int display_set_backlight(int level) { + return (int)syscall_invoke1((uint32_t)level, SYSCALL_DISPLAY_SET_BACKLIGHT); +} + +int display_get_backlight(void) { + return (int)syscall_invoke0(SYSCALL_DISPLAY_GET_BACKLIGHT); +} + +int display_set_orientation(int angle) { + return (int)syscall_invoke1((uint32_t)angle, SYSCALL_DISPLAY_SET_ORIENTATION); +} + +int display_get_orientation(void) { + return (int)syscall_invoke0(SYSCALL_DISPLAY_GET_ORIENTATION); +} + +#ifdef XFRAMEBUFFER + +display_fb_info_t display_get_frame_buffer(void) { + display_fb_info_t info; + syscall_invoke1((uint32_t)&info, SYSCALL_DISPLAY_GET_FB_INFO); + return info; +} + +#else // XFRAMEBUFFER + +void display_wait_for_sync(void) { + syscall_invoke0(SYSCALL_DISPLAY_WAIT_FOR_SYNC); +} + +#endif + +void display_fill(const gfx_bitblt_t *bb) { + syscall_invoke1((uint32_t)bb, SYSCALL_DISPLAY_FILL); +} + +void display_copy_rgb565(const gfx_bitblt_t *bb) { + syscall_invoke1((uint32_t)bb, SYSCALL_DISPLAY_COPY_RGB565); +} + +void display_refresh(void) { syscall_invoke0(SYSCALL_DISPLAY_REFRESH); } + +// ============================================================================= +// usb.h +// ============================================================================= + +#include "usb.h" + +secbool usb_init(const usb_dev_info_t *dev_info) { + return (secbool)syscall_invoke1((uint32_t)dev_info, SYSCALL_USB_INIT); +} + +void usb_deinit(void) { syscall_invoke0(SYSCALL_USB_DEINIT); } + +secbool usb_start(void) { return (secbool)syscall_invoke0(SYSCALL_USB_START); } + +void usb_stop(void) { syscall_invoke0(SYSCALL_USB_STOP); } + +secbool usb_configured(void) { + return (secbool)syscall_invoke0(SYSCALL_USB_CONFIGURED); +} + +// ============================================================================= +// usb_hid.h +// ============================================================================= + +#include "usb_hid.h" + +secbool usb_hid_add(const usb_hid_info_t *hid_info) { + return (secbool)syscall_invoke1((uint32_t)hid_info, SYSCALL_USB_HID_ADD); +} + +secbool usb_hid_can_read(uint8_t iface_num) { + return (secbool)syscall_invoke1((uint32_t)iface_num, + SYSCALL_USB_HID_CAN_READ); +} + +secbool usb_hid_can_write(uint8_t iface_num) { + return (secbool)syscall_invoke1((uint32_t)iface_num, + SYSCALL_USB_HID_CAN_WRITE); +} + +int usb_hid_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { + return (int)syscall_invoke3((uint32_t)iface_num, (uint32_t)buf, len, + SYSCALL_USB_HID_READ); +} + +int usb_hid_write(uint8_t iface_num, const uint8_t *buf, uint32_t len) { + return (int)syscall_invoke3((uint32_t)iface_num, (uint32_t)buf, len, + SYSCALL_USB_HID_WRITE); +} + +int usb_hid_read_select(uint32_t timeout) { + return (int)syscall_invoke1(timeout, SYSCALL_USB_HID_READ_SELECT); +} + +int usb_hid_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len, + int timeout) { + return (int)syscall_invoke4((uint32_t)iface_num, (uint32_t)buf, len, timeout, + SYSCALL_USB_HID_READ_BLOCKING); +} + +int usb_hid_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len, + int timeout) { + return (int)syscall_invoke4((uint32_t)iface_num, (uint32_t)buf, len, timeout, + SYSCALL_USB_HID_WRITE_BLOCKING); +} + +// ============================================================================= +// usb_vcp.h +// ============================================================================= + +#include "usb_vcp.h" + +secbool usb_vcp_add(const usb_vcp_info_t *vcp_info) { + return (secbool)syscall_invoke1((uint32_t)vcp_info, SYSCALL_USB_VCP_ADD); +} + +secbool usb_vcp_can_read(uint8_t iface_num) { + return (secbool)syscall_invoke1((uint32_t)iface_num, + SYSCALL_USB_VCP_CAN_READ); +} + +secbool usb_vcp_can_write(uint8_t iface_num) { + return (secbool)syscall_invoke1((uint32_t)iface_num, + SYSCALL_USB_VCP_CAN_WRITE); +} + +int usb_vcp_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { + return (int)syscall_invoke3((uint32_t)iface_num, (uint32_t)buf, len, + SYSCALL_USB_VCP_READ); +} + +int usb_vcp_write(uint8_t iface_num, const uint8_t *buf, uint32_t len) { + return (int)syscall_invoke3((uint32_t)iface_num, (uint32_t)buf, len, + SYSCALL_USB_VCP_WRITE); +} + +int usb_vcp_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len, + int timeout) { + return (int)syscall_invoke4((uint32_t)iface_num, (uint32_t)buf, len, timeout, + SYSCALL_USB_VCP_READ_BLOCKING); +} + +int usb_vcp_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len, + int timeout) { + return (int)syscall_invoke4((uint32_t)iface_num, (uint32_t)buf, len, timeout, + SYSCALL_USB_VCP_WRITE_BLOCKING); +} + +// ============================================================================= +// usb_webusb.h +// ============================================================================= + +#include "usb_webusb.h" + +secbool usb_webusb_add(const usb_webusb_info_t *webusb_info) { + return (secbool)syscall_invoke1((uint32_t)webusb_info, + SYSCALL_USB_WEBUSB_ADD); +} + +secbool usb_webusb_can_read(uint8_t iface_num) { + return (secbool)syscall_invoke1((uint32_t)iface_num, + SYSCALL_USB_WEBUSB_CAN_READ); +} + +secbool usb_webusb_can_write(uint8_t iface_num) { + return (secbool)syscall_invoke1((uint32_t)iface_num, + SYSCALL_USB_WEBUSB_CAN_WRITE); +} + +int usb_webusb_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { + return (int)syscall_invoke3((uint32_t)iface_num, (uint32_t)buf, len, + SYSCALL_USB_WEBUSB_READ); +} + +int usb_webusb_write(uint8_t iface_num, const uint8_t *buf, uint32_t len) { + return (int)syscall_invoke3((uint32_t)iface_num, (uint32_t)buf, len, + SYSCALL_USB_WEBUSB_WRITE); +} + +int usb_webusb_read_select(uint32_t timeout) { + return (int)syscall_invoke1(timeout, SYSCALL_USB_WEBUSB_READ_SELECT); +} + +int usb_webusb_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len, + int timeout) { + return (int)syscall_invoke4((uint32_t)iface_num, (uint32_t)buf, len, timeout, + SYSCALL_USB_WEBUSB_READ_BLOCKING); +} + +int usb_webusb_write_blocking(uint8_t iface_num, const uint8_t *buf, + uint32_t len, int timeout) { + return (int)syscall_invoke4((uint32_t)iface_num, (uint32_t)buf, len, timeout, + SYSCALL_USB_WEBUSB_WRITE_BLOCKING); +} + +// ============================================================================= +// sdcard.h +// ============================================================================= + +#include "sdcard.h" + +secbool sdcard_power_on(void) { + return (secbool)syscall_invoke0(SYSCALL_SDCARD_POWER_ON); +} + +void sdcard_power_off(void) { syscall_invoke0(SYSCALL_SDCARD_POWER_OFF); } + +secbool sdcard_is_present(void) { + return (secbool)syscall_invoke0(SYSCALL_SDCARD_IS_PRESENT); +} + +uint64_t sdcard_get_capacity_in_bytes(void) { + return syscall_invoke0_ret64(SYSCALL_SDCARD_GET_CAPACITY); +} + +secbool __wur sdcard_read_blocks(uint32_t *dest, uint32_t block_num, + uint32_t num_blocks) { + return (secbool)syscall_invoke3((uint32_t)dest, block_num, num_blocks, + SYSCALL_SDCARD_READ_BLOCKS); +} + +secbool __wur sdcard_write_blocks(const uint32_t *src, uint32_t block_num, + uint32_t num_blocks) { + return (secbool)syscall_invoke3((uint32_t)src, block_num, num_blocks, + SYSCALL_SDCARD_WRITE_BLOCKS); +} + +// ============================================================================= +// unit_variant.h +// ============================================================================= + +bool unit_variant_present(void) { + return (bool)syscall_invoke0(SYSCALL_UNIT_VARIANT_PRESENT); +} +uint8_t unit_variant_get_color(void) { + return (uint8_t)syscall_invoke0(SYSCALL_UNIT_VARIANT_GET_COLOR); +} + +uint8_t unit_variant_get_packaging(void) { + return (uint8_t)syscall_invoke0(SYSCALL_UNIT_VARIANT_GET_PACKAGING); +} + +bool unit_variant_get_btconly(void) { + return (bool)syscall_invoke0(SYSCALL_UNIT_VARIANT_GET_BTCONLY); +} + +bool unit_variant_is_sd_hotswap_enabled(void) { + return (bool)syscall_invoke0(SYSCALL_UNIT_VARIANT_IS_SD_HOTSWAP_ENABLED); +} + +// ============================================================================= +// secret.h +// ============================================================================= + +secbool secret_bootloader_locked(void) { + return (secbool)syscall_invoke0(SYSCALL_SECRET_BOOTLOADER_LOCKED); +} + +// ============================================================================= +// button.h +// ============================================================================= + +#include "button.h" + +uint32_t button_read(void) { return syscall_invoke0(SYSCALL_BUTTON_READ); } + +char button_state_left(void) { + return (char)syscall_invoke0(SYSCALL_BUTTON_STATE_LEFT); +} +char button_state_right(void) { + return (char)syscall_invoke0(SYSCALL_BUTTON_STATE_RIGHT); +} + +// ============================================================================= +// touch.h +// ============================================================================= + +#include "touch.h" + +uint32_t touch_get_event(void) { + return syscall_invoke0(SYSCALL_TOUCH_GET_EVENT); +} + +// ============================================================================= +// haptic.h +// ============================================================================= + +#include "haptic.h" + +void haptic_set_enabled(bool enabled) { + syscall_invoke1((uint32_t)enabled, SYSCALL_HAPTIC_SET_ENABLED); +} + +bool haptic_get_enabled(void) { + return (bool)syscall_invoke0(SYSCALL_HAPTIC_GET_ENABLED); +} + +bool haptic_test(uint16_t duration_ms) { + return (bool)syscall_invoke1(duration_ms, SYSCALL_HAPTIC_TEST); +} + +bool haptic_play(haptic_effect_t effect) { + return (bool)syscall_invoke1((uint32_t)effect, SYSCALL_HAPTIC_PLAY); +} + +bool haptic_play_custom(int8_t amplitude_pct, uint16_t duration_ms) { + return (bool)syscall_invoke2((uint32_t)amplitude_pct, duration_ms, + SYSCALL_HAPTIC_PLAY_CUSTOM); +} + +// ============================================================================= +// optiga.h +// ============================================================================= + +#include "optiga.h" + +optiga_sign_result optiga_sign(uint8_t index, const uint8_t *digest, + size_t digest_size, uint8_t *signature, + size_t max_sig_size, size_t *sig_size) { + return (optiga_sign_result)syscall_invoke6( + index, (uint32_t)digest, digest_size, (uint32_t)signature, max_sig_size, + (uint32_t)sig_size, SYSCALL_OPTIGA_SIGN); +} + +bool optiga_cert_size(uint8_t index, size_t *cert_size) { + return (bool)syscall_invoke2(index, (uint32_t)cert_size, + SYSCALL_OPTIGA_CERT_SIZE); +} + +bool optiga_read_cert(uint8_t index, uint8_t *cert, size_t max_cert_size, + size_t *cert_size) { + return (bool)syscall_invoke4(index, (uint32_t)cert, max_cert_size, + (uint32_t)cert_size, SYSCALL_OPTIGA_READ_CERT); +} + +bool optiga_read_sec(uint8_t *sec) { + return (bool)syscall_invoke1((uint32_t)sec, SYSCALL_OPTIGA_READ_SEC); +} + +bool optiga_random_buffer(uint8_t *dest, size_t size) { + return (bool)syscall_invoke2((uint32_t)dest, size, + SYSCALL_OPTIGA_RANDOM_BUFFER); +} + +#if PYOPT == 0 +void optiga_set_sec_max(void) { syscall_invoke0(SYSCALL_OPTIGA_SET_SEC_MAX); } + +#endif + +// ============================================================================= +// storage.h +// ============================================================================= + +#include "storage.h" + +static PIN_UI_WAIT_CALLBACK storage_init_callback = NULL; + +static void storage_init_callback_wrapper(uint32_t wait, uint32_t progress, + enum storage_ui_message_t message) { + secbool retval = storage_init_callback(wait, progress, message); + syscall_return_from_callback(retval); +} + +void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt, + const uint16_t salt_len) { + storage_init_callback = callback; + + syscall_invoke3((uint32_t)storage_init_callback_wrapper, (uint32_t)salt, + salt_len, SYSCALL_STORAGE_INIT); +} + +void storage_wipe(void) { syscall_invoke0(SYSCALL_STORAGE_WIPE); } +secbool storage_is_unlocked(void) { + return (secbool)syscall_invoke0(SYSCALL_STORAGE_IS_UNLOCKED); +} + +void storage_lock(void) { syscall_invoke0(SYSCALL_STORAGE_LOCK); } + +secbool storage_unlock(const uint8_t *pin, size_t pin_len, + const uint8_t *ext_salt) { + return (secbool)syscall_invoke3((uint32_t)pin, pin_len, (uint32_t)ext_salt, + SYSCALL_STORAGE_UNLOCK); +} + +secbool storage_has_pin(void) { + return (secbool)syscall_invoke0(SYSCALL_STORAGE_HAS_PIN); +} +secbool storage_pin_fails_increase(void) { + return (secbool)syscall_invoke0(SYSCALL_STORAGE_PIN_FAILS_INCREASE); +} + +uint32_t storage_get_pin_rem(void) { + return syscall_invoke0(SYSCALL_STORAGE_GET_PIN_REM); +} + +secbool storage_change_pin(const uint8_t *oldpin, size_t oldpin_len, + const uint8_t *newpin, size_t newpin_len, + const uint8_t *old_ext_salt, + const uint8_t *new_ext_salt) { + return (secbool)syscall_invoke6( + (uint32_t)oldpin, oldpin_len, (uint32_t)newpin, newpin_len, + (uint32_t)old_ext_salt, (uint32_t)new_ext_salt, + SYSCALL_STORAGE_CHANGE_PIN); +} + +void storage_ensure_not_wipe_code(const uint8_t *pin, size_t pin_len) { + syscall_invoke2((uint32_t)pin, pin_len, SYSCALL_STORAGE_ENSURE_NOT_WIPE_CODE); +} + +secbool storage_has_wipe_code(void) { + return (secbool)syscall_invoke0(SYSCALL_STORAGE_HAS_WIPE_CODE); +} + +secbool storage_change_wipe_code(const uint8_t *pin, size_t pin_len, + const uint8_t *ext_salt, + const uint8_t *wipe_code, + size_t wipe_code_len) { + return (secbool)syscall_invoke5((uint32_t)pin, pin_len, (uint32_t)ext_salt, + (uint32_t)wipe_code, wipe_code_len, + SYSCALL_STORAGE_CHANGE_WIPE_CODE); +} + +secbool storage_has(const uint16_t key) { + return (secbool)syscall_invoke1(key, SYSCALL_STORAGE_HAS); +} + +secbool storage_get(const uint16_t key, void *val, const uint16_t max_len, + uint16_t *len) { + return (secbool)syscall_invoke4(key, (uint32_t)val, max_len, (uint32_t)len, + SYSCALL_STORAGE_GET); +} + +secbool storage_set(const uint16_t key, const void *val, const uint16_t len) { + return (secbool)syscall_invoke3(key, (uint32_t)val, len, SYSCALL_STORAGE_SET); +} + +secbool storage_delete(const uint16_t key) { + return (secbool)syscall_invoke1(key, SYSCALL_STORAGE_DELETE); +} + +secbool storage_set_counter(const uint16_t key, const uint32_t count) { + return (secbool)syscall_invoke2(key, count, SYSCALL_STORAGE_SET_COUNTER); +} + +secbool storage_next_counter(const uint16_t key, uint32_t *count) { + return (secbool)syscall_invoke2(key, (uint32_t)count, + SYSCALL_STORAGE_NEXT_COUNTER); +} + +// ============================================================================= +// entropy.h +// ============================================================================= + +void entropy_get(uint8_t *buf) { + syscall_invoke1((uint32_t)buf, SYSCALL_ENTROPY_GET); +} + +// ============================================================================= +// translations.h +// ============================================================================= + +#include "translations.h" + +bool translations_write(const uint8_t *data, uint32_t offset, uint32_t len) { + return (bool)syscall_invoke3((uint32_t)data, offset, len, + SYSCALL_TRANSLATIONS_WRITE); +} + +const uint8_t *translations_read(uint32_t *len, uint32_t offset) { + return (const uint8_t *)syscall_invoke2((uint32_t)len, offset, + SYSCALL_TRANSLATIONS_READ); +} + +void translations_erase(void) { syscall_invoke0(SYSCALL_TRANSLATIONS_ERASE); } + +uint32_t translations_area_bytesize(void) { + return syscall_invoke0(SYSCALL_TRANSLATIONS_AREA_BYTESIZE); +} + +// ============================================================================= +// rng.h +// ============================================================================= + +#include "rng.h" + +uint32_t rng_get(void) { return syscall_invoke0(SYSCALL_RNG_GET); } + +// ============================================================================= +// fwutils.h +// ============================================================================= + +#include "fwutils.h" + +secbool firmware_get_vendor(char *buff, size_t buff_size) { + return syscall_invoke2((uint32_t)buff, buff_size, + SYSCALL_FIRMWARE_GET_VENDOR); +} + +static firmware_hash_callback_t firmware_hash_callback = NULL; + +static void firmware_hash_callback_wrapper(void *context, uint32_t progress, + uint32_t total) { + firmware_hash_callback(context, progress, total); + syscall_return_from_callback(0); +} + +secbool firmware_calc_hash(const uint8_t *challenge, size_t challenge_len, + uint8_t *hash, size_t hash_len, + firmware_hash_callback_t callback, + void *callback_context) { + firmware_hash_callback = callback; + + return syscall_invoke6((uint32_t)challenge, challenge_len, (uint32_t)hash, + hash_len, (uint32_t)firmware_hash_callback_wrapper, + (uint32_t)callback_context, + SYSCALL_FIRMWARE_CALC_HASH); +} +#endif diff --git a/core/embed/trezorhal/stm32f4/systask.c b/core/embed/trezorhal/stm32f4/systask.c new file mode 100644 index 00000000000..56456f7c08b --- /dev/null +++ b/core/embed/trezorhal/stm32f4/systask.c @@ -0,0 +1,639 @@ +/* + * 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 + +#include "bootutils.h" +#include "irq.h" +#include "mpu.h" +#include "syscall.h" +#include "systask.h" +#include "system.h" + +#ifdef KERNEL_MODE + +// Disable stack protector for this file since it may interfere +// with the stack manipulation and fault handling +#pragma GCC optimize("no-stack-protector") + +#define STK_FRAME_R0 0 +#define STK_FRAME_R1 1 +#define STK_FRAME_R2 2 +#define STK_FRAME_R3 3 +#define STK_FRAME_R12 4 +#define STK_FRAME_LR 5 +#define STK_FRAME_RET_ADDR 6 +#define STK_FRAME_XPSR 7 + +// Task manager state +typedef struct { + // Error handler called when a kernel task terminates + systask_error_handler_t error_handler; + // Background kernel task + systask_t kernel_task; + // Currently running task + systask_t* active_task; + // Task to be scheduled next + systask_t* waiting_task; +} systask_scheduler_t; + +// Kernel stack base pointer defined in linker script +extern uint8_t _sstack; +extern uint8_t _estack; + +// Global task manager state +static systask_scheduler_t g_systask_scheduler = { + // This static initialization is required for exception handling + // to function correctly before the scheduler is initialized. + .active_task = &g_systask_scheduler.kernel_task, + .waiting_task = &g_systask_scheduler.kernel_task, + .kernel_task = { + .sp_lim = (uint32_t)&_sstack, + }}; + +void systask_scheduler_init(systask_error_handler_t error_handler) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + memset(scheduler, 0, sizeof(systask_scheduler_t)); + + scheduler->error_handler = error_handler; + scheduler->active_task = &scheduler->kernel_task; + scheduler->waiting_task = scheduler->active_task; + + scheduler->kernel_task.sp_lim = (uint32_t)&_sstack; + + // SVCall priority should be the lowest since it is + // generally a blocking operation + NVIC_SetPriority(SVCall_IRQn, IRQ_PRI_LOWEST); + NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_LOWEST); + + // Enable BusFault and UsageFault handlers + SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk); +} + +systask_t* systask_active(void) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + return scheduler->active_task; +} + +static void systask_yield(void) { + bool handler_mode = (__get_IPSR() & IPSR_ISR_Msk) != 0; + + if (handler_mode) { + SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; + __DSB(); + } else { + // SVC_SYSTASK_YIELD is the only SVC that is allowed to be invoked from + // kernel itself, and it is used to start the unprivileged application code. + __asm__ volatile("svc %[svid]\n" + : // no output + : [svid] "i"(SVC_SYSTASK_YIELD) + : "memory"); + } +} + +void systask_yield_to(systask_t* task) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + irq_key_t irq_key = irq_lock(); + scheduler->waiting_task = task; + irq_unlock(irq_key); + + systask_yield(); +} + +void systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size) { + memset(task, 0, sizeof(systask_t)); + task->sp = stack_ptr + stack_size; + task->sp_lim = stack_ptr + 256; + task->exc_return = 0xFFFFFFED; // Thread mode, use PSP, pop FP context + task->mpu_mode = MPU_MODE_APP; +} + +uint32_t* systask_push_data(systask_t* task, const void* data, size_t size) { + if (task->sp < task->sp_lim) { + // Stack overflow + return NULL; + } + + uint32_t stack_remaining = task->sp - task->sp_lim; + + if (stack_remaining < size) { + // Not enough space on the stack + return NULL; + } + + task->sp -= size; + + if (data != NULL) { + memcpy((void*)task->sp, data, size); + } else { + memset((void*)task->sp, 0, size); + } + + return (void*)task->sp; +} + +void systask_pop_data(systask_t* task, size_t size) { task->sp += size; } + +bool systask_push_call(systask_t* task, void* entrypoint, uint32_t arg1, + uint32_t arg2, uint32_t arg3) { + uint32_t original_sp = task->sp; + + // Align stack pointer to 8 bytes + task->sp &= ~7; + + // FP extension context + if (systask_push_data(task, NULL, 0x48) == NULL) { + goto cleanup; + } + + // Standard exception frame + uint32_t* stk_frame = systask_push_data(task, NULL, 0x20); + if (stk_frame == NULL) { + goto cleanup; + } + + // Registers r4-r11 + if (systask_push_data(task, NULL, 0x20) == NULL) { + goto cleanup; + } + // Registers s16-s31 + if (systask_push_data(task, NULL, 0x40) == NULL) { + goto cleanup; + } + + // Return to thread mode, use PSP, pop FP context + task->exc_return = 0xFFFFFFED; + + stk_frame[STK_FRAME_R0] = arg1; + stk_frame[STK_FRAME_R1] = arg2; + stk_frame[STK_FRAME_R2] = arg3; + stk_frame[STK_FRAME_RET_ADDR] = (uint32_t)entrypoint & ~1; + stk_frame[STK_FRAME_XPSR] = 0x01000000; // T (Thumb state) bit set + + return true; + +cleanup: + task->sp = original_sp; + return false; +} + +static void systask_kill(systask_t* task) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + task->killed = 1; + + if (task == &scheduler->kernel_task) { + // Call panic handler + if (scheduler->error_handler != NULL) { + scheduler->error_handler(&task->pminfo); + } + secure_shutdown(); + } else if (task == scheduler->active_task) { + // Switch to the kernel task + systask_yield_to(&scheduler->kernel_task); + } +} + +void systask_exit(systask_t* task, int exit_code) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + if (task == NULL) { + bool handler_mode = (__get_IPSR() & IPSR_ISR_Msk) != 0; + task = handler_mode ? &scheduler->kernel_task : scheduler->active_task; + } + + systask_postmortem_t* pminfo = &task->pminfo; + + memset(pminfo, 0, sizeof(systask_postmortem_t)); + pminfo->reason = TASK_TERM_REASON_EXIT; + pminfo->privileged = (task == &scheduler->kernel_task); + pminfo->exit.code = exit_code; + + systask_kill(task); +} + +void systask_exit_error(systask_t* task, const char* title, const char* message, + const char* footer) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + if (task == NULL) { + bool handler_mode = (__get_IPSR() & IPSR_ISR_Msk) != 0; + task = handler_mode ? &scheduler->kernel_task : scheduler->active_task; + } + + systask_postmortem_t* pminfo = &task->pminfo; + + memset(pminfo, 0, sizeof(systask_postmortem_t)); + pminfo->reason = TASK_TERM_REASON_ERROR; + pminfo->privileged = (task == &scheduler->kernel_task); + + if (title != NULL) { + strncpy(pminfo->error.title, title, sizeof(pminfo->error.title) - 1); + } + + if (message != NULL) { + strncpy(pminfo->error.message, message, sizeof(pminfo->error.message) - 1); + } + + if (footer != NULL) { + strncpy(pminfo->error.footer, footer, sizeof(pminfo->error.footer) - 1); + } + + systask_kill(task); +} + +void systask_exit_fatal(systask_t* task, const char* message, const char* file, + int line) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + if (task == NULL) { + bool handler_mode = (__get_IPSR() & IPSR_ISR_Msk) != 0; + task = handler_mode ? &scheduler->kernel_task : scheduler->active_task; + } + + systask_postmortem_t* pminfo = &task->pminfo; + + memset(pminfo, 0, sizeof(systask_postmortem_t)); + pminfo->reason = TASK_TERM_REASON_FATAL; + pminfo->privileged = (task == &scheduler->kernel_task); + + if (message != NULL) { + strncpy(pminfo->fatal.expr, message, sizeof(pminfo->fatal.expr) - 1); + } + + if (file != NULL) { + strncpy(pminfo->fatal.file, file, sizeof(pminfo->fatal.file) - 1); + } + + pminfo->fatal.line = line; + + systask_kill(task); +} + +// Terminate active task from fault/exception handler +__attribute((used)) static void systask_exit_fault(bool privileged, + uint32_t sp) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + + systask_scheduler_t* scheduler = &g_systask_scheduler; + + systask_t* task = + privileged ? &scheduler->kernel_task : scheduler->active_task; + + systask_postmortem_t* pminfo = &task->pminfo; + + // Do not overwrite the reason if it is already set to fault + // (exception handlers may call this function multiple times, and + // we want to preserve the first reason) + if (pminfo->reason != TASK_TERM_REASON_FAULT) { + pminfo->reason = TASK_TERM_REASON_FAULT; + pminfo->privileged = privileged; + pminfo->fault.sp = sp; +#if !(defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)) + pminfo->fault.sp_lim = task->sp_lim; +#endif + pminfo->fault.irqn = (__get_IPSR() & IPSR_ISR_Msk) - 16; + pminfo->fault.cfsr = SCB->CFSR; + pminfo->fault.mmfar = SCB->MMFAR; + pminfo->fault.bfar = SCB->BFAR; + pminfo->fault.hfsr = SCB->HFSR; + } + + systask_kill(task); + + mpu_restore(mpu_mode); +} + +// C part of PendSV handler that switches tasks +// +// `sp` is the stack pointer of the current task +// `sp_lim` is the stack pointer limit of the current task +// `exc_return` is the execution state of the current task +// +// Returns the context struct of the next task +__attribute((no_stack_protector, used)) static uint32_t scheduler_pendsv( + uint32_t sp, uint32_t sp_lim, uint32_t exc_return) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + // Save the current task context + systask_t* prev_task = scheduler->active_task; + prev_task->sp = sp; +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + // sp_lim is not valid on ARMv7-M + prev_task->sp_lim = sp_lim; +#endif + prev_task->exc_return = exc_return; + prev_task->mpu_mode = mpu_get_mode(); + + // Switch to the next task + scheduler->active_task = scheduler->waiting_task; + + // Load the scheduled task context + systask_t* next_task = scheduler->active_task; + + // Set task privilege level + uint32_t control = __get_CONTROL(); + if (next_task == &scheduler->kernel_task) { + control &= ~CONTROL_nPRIV_Msk; + } else { + control |= CONTROL_nPRIV_Msk; + } + __set_CONTROL(control); + + // Setup the MPU for the new task + mpu_reconfig(next_task->mpu_mode); + + return (uint32_t)next_task; +} + +__attribute__((naked, no_stack_protector)) void PendSV_Handler(void) { + __asm__ volatile( + "LDR R0, =%[active_task] \n" + "LDR R1, =%[waiting_task]\n" + "CMP R0, R1 \n" + "BEQ 3f \n" // No task switch needed + + "LDR R0, [R0] \n" // R0 = active_task + "LDR R0, [R0, #12] \n" // R0 = active_task->killed + "CMP R0, #0 \n" + "BEQ 1f \n" // =0 => normal processing + + // We are switching from a killed task to the kernel task. + // Since the reason might be a stack overflow, we must not + // attempt to save the task context. + + "LDR R1, = 0xE000EF34 \n" // FPU->FPCCR + "LDR R0, [R1] \n" + "BIC R0, R0, #1 \n" // Clear LSPACT to suppress later lazy + "STR R0, [R1] \n" // stacking to the killed task stack + + "MOV R0, #0 \n" // Skip context save + "MOV R1, R0 \n" // + "MOV R2, R0 \n" // + "B 2f \n" // + + "1: \n" + + // Save the current task context on its stack before switching + + "TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP) + +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + "ITTEE EQ \n" + "MRSEQ R0, MSP \n" // Get current SP + "MRSEQ R1, MSPLIM \n" // Get current SP Limit + "MRSNE R0, PSP \n" + "MRSNE R1, PSPLIM \n" +#else + "ITE EQ \n" + "MRSEQ R0, MSP \n" // Get current SP + "MRSNE R0, PSP \n" + "MOV R1, #0 \n" // (fake SPLIM) +#endif + "IT EQ \n" // If using main stack: + "SUBEQ SP, SP, #0x60 \n" // reserve space for R4-11 and S16-S31 + + "MOV R2, LR \n" // Get current EXC_RETURN + + "STMDB R0!, {R4-R11} \n" // Save R4-R11 to SP Frame Stack + "TST LR, #0x10 \n" // Check EXC_RETURN.Ftype bit to see if + // the current thread has a FP context + "IT EQ \n" + "VSTMDBEQ R0!, {S16-S31} \n" // If so, save S16-S31 FP addition + // context, that will also trigger lazy + // fp context preservation of S0-S15 + "2: \n" + + "BL scheduler_pendsv \n" // Save SP value of current task + "LDR LR, [R0, #8] \n" // Get the EXC_RETURN value + "LDR R1, [R0, #4] \n" // Get the SP_LIM value + "LDR R0, [R0, #0] \n" // Get the SP value + + "TST LR, #0x10 \n" // Check EXC_RETURN.Ftype bit to see if + // the next thread has a FP context + "IT EQ \n" + "VLDMIAEQ R0!, {S16-S31} \n" // If so, restore S16-S31 + "LDMIA R0!, {R4-R11} \n" // Restore R4-R11 + + "TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP) +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + "ITEE EQ \n" + "MSREQ MSP, R0 \n" // Update MSP + "MSRNE PSPLIM, R1 \n" // Update PSPLIM & PSP + "MSRNE PSP, R0 \n" +#else + "ITE EQ \n" + "MSREQ MSP, R0 \n" // Update the MSP + "MSRNE PSP, R0 \n" // Update the PSP +#endif + "3: " + "BX LR \n" + : // No output + : [active_task] "i"(&g_systask_scheduler.active_task), // Input + [waiting_task] "i"(&g_systask_scheduler.waiting_task) // Input + : // Clobber + ); +} + +__attribute__((no_stack_protector, used)) static uint32_t svc_handler( + uint32_t* stack, uint32_t* msp, uint32_t exc_return, uint32_t r4, + uint32_t r5, uint32_t r6) { + uint8_t svc_number = ((uint8_t*)stack[6])[-2]; + +#ifdef SYSCALL_DISPATCH + uint32_t args[6] = {stack[0], stack[1], stack[2], stack[3], r4, r5}; +#endif + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + + switch (svc_number) { +#ifdef SYSTEM_VIEW + case SVC_GET_DWT_CYCCNT: + cyccnt_cycles = *DWT_CYCCNT_ADDR; + break; +#endif + case SVC_SYSTASK_YIELD: + // Yield to the waiting task + systask_yield(); + break; +#ifdef SYSCALL_DISPATCH + case SVC_SYSCALL: + syscall_handler(args, r6); + stack[0] = args[0]; + stack[1] = args[1]; + break; + case SVC_CALLBACK_RETURN: + // g_return_value = args[0] + // exc_return = return_from_callback; + mpu_restore(mpu_mode); + return_from_app_callback(args[0], msp); + break; +#endif + default: + break; + } + + mpu_restore(mpu_mode); + return exc_return; +} + +__attribute((naked, no_stack_protector)) void SVC_Handler(void) { + __asm__ volatile( + "TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP) + "ITE EQ \n" + "MRSEQ R0, MSP \n" // `stack` argument + "MRSNE R0, PSP \n" + "TST LR, #0x20 \n" + "IT EQ \n" + "ADDEQ R0, R0, #0x40 \n" + "MRS R1, MSP \n" // `msp` argument + "MOV R2, LR \n" // `exc_return` argument + "MOV R3, R4 \n" // 'r4' argument + "PUSH {R5, R6} \n" // 'r5' and 'r6' arguments on stack + "BL svc_handler \n" + "POP {R5, R6} \n" + "BX R0 \n" // Branch to the returned value + ); +} + +__attribute__((naked, no_stack_protector)) void HardFault_Handler(void) { + // A HardFault may also be caused by exception escalation. + // To ensure we have enough space to handle the exception, + // we set the stack pointer to the end of the stack. + + __asm__ volatile( + "MRS R1, MSP \n" // R1 = MSP + "LDR R0, =%[estack] \n" // Reset main stack + "MSR MSP, R0 \n" // + "MOV R0, #1 \n" // R0 = 1 (Privileged) + "B systask_exit_fault \n" // Exit task with fault + : + : [estack] "i"(&_estack) + : "memory"); +} + +__attribute__((naked, no_stack_protector)) void MemManage_Handler(void) { + __asm__ volatile( + "TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP) + "ITTEE EQ \n" + "MOVEQ R0, #1 \n" // R0 = 1 (Privileged) + "MRSEQ R1, MSP \n" // R1 = MSP + "MOVNE R0, #0 \n" // R0 = 0 (Unprivileged) + "MRSNE R1, PSP \n" // R1 = PSP +#if !(defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)) + "CMP R0, #0 \n" + "BEQ 1f \n" // Skip stack ptr checking for PSP + "LDR R2, =%[sstack] \n" + "CMP R1, R2 \n" // Check if PSP is below the stack + "ITT LO \n" // base + "LDRLO R2, =%[estack] \n" + "MSRLO MSP, R2 \n" // Reset MSP + "1: \n" +#endif + "B systask_exit_fault \n" // Exit task with fault + : + : [estack] "i"(&_estack), [sstack] "i"((uint32_t)&_sstack + 256) + : "memory"); +} + +__attribute__((naked, no_stack_protector)) void BusFault_Handler(void) { + __asm__ volatile( + "TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP) + "ITTEE EQ \n" + "MOVEQ R0, #1 \n" // R0 = 1 (Privileged) + "MRSEQ R1, MSP \n" // R1 = MSP + "MOVNE R0, #0 \n" // R0 = 0 (Unprivileged) + "MRSNE R1, PSP \n" // R1 = PSP + "B systask_exit_fault \n" // Exit task with fault + ); +} + +__attribute__((naked, no_stack_protector)) void UsageFault_Handler(void) { + __asm__ volatile( + "TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP) + "ITTT NE \n" + "MOVNE R0, #0 \n" // R0 = 0 (Unprivileged) + "MRSNE R1, PSP \n" // R1 = PSP + "BNE systask_exit_fault \n" // Exit task with fault +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + "MRS R1, MSP \n" // R1 = MSP + "LDR R0, =0xE000ED28 \n" // SCB->CFSR + "LDR R0, [R0] \n" + "TST R0, #0x100000 \n" // STKOF bit set? + "ITT NE \n" + "LDRNE R0, =%[estack] \n" // Reset main stack in case of stack + "MSRNE MSP, R0 \n" // overflow +#endif + "MOV R0, #1 \n" // R0 = 1 (Privileged) + "B systask_exit_fault \n" // Exit task with fault + : + : [estack] "i"(&_estack) + : "memory"); +} + +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) +__attribute__((naked, no_stack_protector)) void SecureFault_Handler(void) { + __asm__ volatile( + "TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP) + "ITTEE EQ \n" + "MOVEQ R0, #1 \n" // R0 = 1 (Privileged) + "MRSEQ R1, MSP \n" // R1 = MSP + "MOVNE R0, #0 \n" // R0 = 0 (Unprivileged) + "MRSNE R1, PSP \n" // R1 = PSP + "B systask_exit_fault \n" // Exit task with fault + ); +} +#endif + +#ifdef STM32U5 +void GTZC_IRQHandler(void) { systask_exit_fault(true, __get_MSP()); } +#endif + +void NMI_Handler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); +#ifdef STM32U5 + if ((RCC->CIFR & RCC_CIFR_CSSF) != 0) { +#else + if ((RCC->CIR & RCC_CIR_CSSF) != 0) { +#endif + // Clock Security System triggered NMI + systask_exit_fault(true, __get_MSP()); + } + mpu_restore(mpu_mode); +} + +// from util.s +extern void shutdown_privileged(void); + +void PVD_PVM_IRQHandler(void) { + mpu_reconfig(MPU_MODE_DEFAULT); +#ifdef BACKLIGHT_PWM_TIM + // Turn off display backlight + BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = 0; +#endif + shutdown_privileged(); +} + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/system.c b/core/embed/trezorhal/stm32f4/system.c new file mode 100644 index 00000000000..351c359b0b5 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/system.c @@ -0,0 +1,310 @@ +/* + * 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 "system.h" +#include "bootutils.h" +#include "mpu.h" +#include "systask.h" +#include "systick.h" +#include "systimer.h" + +#ifdef KERNEL_MODE + +void system_init(systask_error_handler_t error_handler) { + mpu_init(); + mpu_reconfig(MPU_MODE_DEFAULT); + systask_scheduler_init(error_handler); + systick_init(); + systimer_init(); +} + +void system_exit(int exitcode) { systask_exit(NULL, exitcode); } + +void system_exit_error(const char* title, const char* message, + const char* footer) { + systask_exit_error(NULL, title, message, footer); +} + +void system_exit_fatal(const char* message, const char* file, int line) { + systask_exit_fatal(NULL, message, file, line); +} + +#endif // KERNEL_MODE + +#ifndef HardFault_IRQn +#define HardFault_IRQn (-13) // not defined in stm32lib/cmsis/stm32429xx.h +#endif + +#ifdef STM32U5 +const char* system_fault_message(const system_fault_t* fault) { + switch (fault->irqn) { + case HardFault_IRQn: + return "(HF)"; + case MemoryManagement_IRQn: + return "(MM)"; + case BusFault_IRQn: + return "(BF)"; + case UsageFault_IRQn: + return (fault->cfsr & SCB_CFSR_STKOF_Msk) ? "(SO)" : "(UF)"; + case SecureFault_IRQn: + return "(SF)"; + case GTZC_IRQn: + return "(IA)"; + case NonMaskableInt_IRQn: + return "(CS)"; + default: + return "(FAULT)"; + } +} +#else // STM32U5 +const char* system_fault_message(const system_fault_t* fault) { + switch (fault->irqn) { + case HardFault_IRQn: + return "(HF)"; + case MemoryManagement_IRQn: + return (fault->sp < fault->sp_lim) ? "(SO)" : "(MM)"; + case BusFault_IRQn: + return "(BF)"; + case UsageFault_IRQn: + return "(UF)"; + case NonMaskableInt_IRQn: + return "(CS)"; + default: + return "(FAULT)"; + } +} +#endif // STM32U5 + +__attribute__((used)) static void emergency_reset(void) { + // TODO: reset peripherals (at least DMA, DMA2D) + + // Disable all NVIC interrupts and clear pending flags + // so later the global interrupt can be re-enabled without + // firing any pending interrupt + for (int irqn = 0; irqn < 255; irqn++) { + NVIC_DisableIRQ(irqn); + NVIC_ClearPendingIRQ(irqn); + } + + // Disable SysTick + SysTick->CTRL = 0; + + // Clear PENDSV flag to prevent the PendSV_Handler call + SCB->ICSR &= ~SCB_ICSR_PENDSVSET_Msk; + + // Clear SCB->SHCSR exception flags so we can return back + // to thread mode without any exception active + + uint32_t preserved_flag = 0; + + switch ((__get_IPSR() & IPSR_ISR_Msk) - 16) { + case MemoryManagement_IRQn: + preserved_flag = SCB_SHCSR_MEMFAULTACT_Msk; + break; + case BusFault_IRQn: + preserved_flag = SCB_SHCSR_BUSFAULTACT_Msk; + break; + case UsageFault_IRQn: + preserved_flag = SCB_SHCSR_USGFAULTACT_Msk; + break; + case PendSV_IRQn: + preserved_flag = SCB_SHCSR_PENDSVACT_Msk; + break; + case SysTick_IRQn: + preserved_flag = SCB_SHCSR_SYSTICKACT_Msk; + break; + case SVCall_IRQn: + preserved_flag = SCB_SHCSR_SVCALLACT_Msk; + break; + case HardFault_IRQn: + default: + break; + } + + const uint32_t cleared_flags = + SCB_SHCSR_MEMFAULTACT_Msk | SCB_SHCSR_BUSFAULTACT_Msk | + SCB_SHCSR_USGFAULTACT_Msk | SCB_SHCSR_SVCALLACT_Msk | + SCB_SHCSR_MONITORACT_Msk | SCB_SHCSR_PENDSVACT_Msk | + SCB_SHCSR_SYSTICKACT_Msk; + + SCB->SHCSR &= ~(cleared_flags & ~preserved_flag); +} + +__attribute((naked, no_stack_protector)) void system_emergency_rescue( + systask_error_handler_t error_handler, const systask_postmortem_t* pminfo) { + extern uint32_t __stack_chk_guard; + + __asm__ volatile( + "MOV R5, R1 \n" // R5 = pminfo + "MOV R6, R0 \n" // R6 = error_handler + + "CPSID I \n" // Disable interrupts + + // -------------------------------------------------------------- + // Disable MPU + // -------------------------------------------------------------- + + "DMB 0xF \n" // Data memory barrier + "LDR R0, =0xE000ED94 \n" // MPU->CTRL + "MOV R1, #0 \n" + "STR R1, [R0] \n" // Disable MPU + + // -------------------------------------------------------------- + // Setup new stack + // -------------------------------------------------------------- + + "LDR R0, =_estack \n" // Setup new stack + "MSR MSP, R0 \n" // Set MSP +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + "LDR R0, =_sstack \n" + "ADD R0, R0, #256 \n" // Add safety margin + "MSR MSPLIM, R0 \n" // Set MSPLIM +#endif + + // -------------------------------------------------------------- + // Copy pminfo to new stack + // -------------------------------------------------------------- + + "LDR R2, =%[PMINFO_SIZE] \n" // Copy pminfo to new stack + "SUB SP, R2 \n" // Allocate space for pminfo + "MOV R0, SP \n" // Destination + "MOV R1, R5 \n" // Source + "MOV R5, R0 \n" // R5 = pminfo on the new stack + "BL memcpy \n" + + // -------------------------------------------------------------- + // Save stack protector guard + // -------------------------------------------------------------- + + "LDR R0, =%[STK_GUARD] \n" // Save stack protector guard + "LDR R7, [R0] \n" // R7 = __stack_chk_guard + + // -------------------------------------------------------------- + // Clear .bss, initialize .data, ... + // -------------------------------------------------------------- + + "LDR R0, =bss_start \n" // Clear .bss + "MOV R1, #0 \n" + "LDR R2, =bss_end \n" + "SUB R2, R2, R0 \n" + "BL memset \n" + + "LDR R0, =data_vma \n" // Initialize .data + "LDR R1, =data_lma \n" + "LDR R2, =data_size \n" + "BL memcpy \n" + +#ifdef STM32U5 + "LDR R0, =confidential_vma \n" // Initialize .confidental + "LDR R1, =confidential_lma \n" + "LDR R2, =confidential_size \n" + "BL memcpy \n" +#endif + + // -------------------------------------------------------------- + // Restore stack protector guard + // -------------------------------------------------------------- + + "LDR R0, =%[STK_GUARD] \n" // Restore stack protector guard + "STR R7, [R0] \n" + + // -------------------------------------------------------------- + // Reset critical hardware so we can safely enable interrupts + // -------------------------------------------------------------- + + "BL emergency_reset \n" + + "CPSIE I \n" // Re-enable interrupts + + // -------------------------------------------------------------- + // Clear all VFP registers + // -------------------------------------------------------------- + + "LDR R1, = 0xE000EF34 \n" // FPU->FPCCR + "LDR R0, [R1] \n" + "BIC R0, R0, #1 \n" // Clear LSPACT to suppress lazy + // stacking + "STR R0, [R1] \n" + + // TODO: clear VFP registers (maybe for ARMV7-M only) + + // -------------------------------------------------------------- + // Clear R7-R11 registers + // -------------------------------------------------------------- + + "MOV R0, #0 \n" + "MOV R7, R0 \n" + "MOV R8, R0 \n" + "MOV R9, R0 \n" + "MOV R10, R0 \n" + "MOV R11, R0 \n" + + // -------------------------------------------------------------- + // Check if we are in thread mode and if yes, jump to error_handler + // -------------------------------------------------------------- + + "LDR R1, =0x1FF \n" // Get lower 9 bits of IPSR + "MRS R0, IPSR \n" + "ANDS R0, R0, R1 \n" + "CMP R0, #0 \n" // == 0 if in thread mode + "ITTT EQ \n" + "MOVEQ R0, R5 \n" // R0 = pminfo + "LDREQ LR, =secure_shutdown\n" + "BXEQ R6 \n" // jump to error_handler directly + + // -------------------------------------------------------------- + // Return from exception to thread mode + // -------------------------------------------------------------- + + "MOV R0, SP \n" // Align stack pointer to 8 bytes + "AND R0, R0, #~7 \n" + "MOV SP, R0 \n" + "SUB SP, SP, #32 \n" // Allocate space for the stack frame + + "MOV R0, #0 \n" + "STR R5, [SP, #0] \n" // future R0 = pminfo + "STR R0, [SP, #4] \n" // future R1 = 0 + "STR R0, [SP, #8] \n" // future R2 = 0 + "STR R0, [SP, #12] \n" // future R3 = 0 + "STR R0, [SP, #16] \n" // future R12 = 0 + "LDR R1, =secure_shutdown\n" + "STR R0, [SP, #20] \n" // future LR = secure_shutdown() + "BIC R6, R6, #1 \n" + "STR R6, [SP, #24] \n" // return address = error_handler() + "LDR R1, = 0x01000000 \n" // THUMB bit set + "STR R1, [SP, #28] \n" // future xPSR + + "MOV R4, R0 \n" // Clear registers R4-R6 + "MOV R5, R0 \n" // (R7-R11 are already cleared) + "MOV R6, R0 \n" + + "MRS R0, CONTROL \n" // Clear SPSEL to use MSP for thread + "BIC R0, R0, #3 \n" // Clear nPRIV to run in privileged mode + "MSR CONTROL, R1 \n" + + "LDR LR, = 0xFFFFFFF9 \n" // Return to Secure Thread mode, use MSP + "BX LR \n" + : // no output + : [PMINFO_SIZE] "i"(sizeof(systask_postmortem_t)), + [STK_GUARD] "i"(&__stack_chk_guard) + : // no clobber + ); +} diff --git a/core/embed/trezorhal/stm32f4/systick.c b/core/embed/trezorhal/stm32f4/systick.c index 5afa8a5bfca..5bfbe2cac29 100644 --- a/core/embed/trezorhal/stm32f4/systick.c +++ b/core/embed/trezorhal/stm32f4/systick.c @@ -1,5 +1,3 @@ -// clang-format off - /* * This file is part of the Trezor project, https://trezor.io/ * @@ -19,52 +17,201 @@ * along with this program. If not, see . */ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2013, 2014 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ +#include +#include #include "irq.h" +#include "mpu.h" +#include "platform.h" +#include "systemview.h" + #include "systick.h" +#include "systick_internal.h" +#include "systimer.h" -#ifdef RDI - #include "random_delays.h" -#endif +#ifdef KERNEL_MODE -#include "systemview.h" +// SysTick driver state +typedef struct { + // Set if the driver is initialized + bool initialized; + // Number of hw cycles per millisecond (tick period) + uint32_t cycles_per_ms; + // Number of hw cycles per microsecond + uint32_t cycles_per_us; + // Current tick value in hardware cycles + volatile uint64_t cycles; + // Number of ticks (ms) since the system start + volatile uint32_t ticks; +} systick_driver_t; + +static systick_driver_t g_systick_driver = { + .initialized = false, +}; + +void systick_init(void) { + systick_driver_t* drv = &g_systick_driver; + + if (drv->initialized) { + return; + } + + drv->cycles = 0; + drv->ticks = 0; + + // Set 1ms tick period + drv->cycles_per_ms = HAL_RCC_GetSysClockFreq() / 1000; + drv->cycles_per_us = drv->cycles_per_ms / 1000; + + // Initialize and enable SysTick timer + SysTick_Config(drv->cycles_per_ms); + + // We need to ensure that SysTick has the expected priority. + // The SysTick priority is configured in the boardloader, + // and some early versions didn't set this properly. + NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_NORMAL); + + drv->initialized = true; +} + +void systick_deinit(void) { + systick_driver_t* drv = &g_systick_driver; + + if (!drv->initialized) { + return; + } + + NVIC_DisableIRQ(SysTick_IRQn); + SysTick->CTRL = 0; + NVIC_ClearPendingIRQ(SysTick_IRQn); + + drv->initialized = false; +} + +void systick_update_freq(void) { + systick_driver_t* drv = &g_systick_driver; + + if (!drv->initialized) { + return; + } + + uint32_t clock_freq = HAL_RCC_GetSysClockFreq(); + drv->cycles_per_ms = clock_freq / 1000; + drv->cycles_per_us = drv->cycles_per_ms / 1000; + SysTick_Config(drv->cycles_per_ms); + + // We need to ensure that SysTick has the expected priority. + // The SysTick priority is configured in the boardloader, + // and some early versions didn't set this properly. + NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_NORMAL); +} + +uint64_t systick_cycles(void) { + systick_driver_t* drv = &g_systick_driver; + + irq_key_t irq_key = irq_lock(); + + // Current value of the SysTick counter + uint32_t val = SysTick->VAL; + + // Check if the SysTick has already counted down to 0 or wrapped around + // Reading CTRL register automatically clears COUNTFLAG + if ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) != 0) { + // Re-read the current value of the SysTick counter + val = SysTick->VAL; + // Update the hardware cycles counter + // Since we have cleared COUNTFLAG, SysTick_Handler will not increment + drv->cycles += drv->cycles_per_ms; + // Increment regular ticks counter + drv->ticks++; + } + + uint64_t cycles = drv->cycles + ((val > 0) ? (drv->cycles_per_ms - val) : 0); + + irq_unlock(irq_key); + + return cycles; +} + +uint64_t systick_us_to_cycles(uint64_t us) { + systick_driver_t* drv = &g_systick_driver; + + return us * drv->cycles_per_us; +} + +uint32_t systick_ms(void) { + systick_driver_t* drv = &g_systick_driver; + + return drv->ticks; +} -extern __IO uint32_t uwTick; +uint64_t systick_us(void) { + systick_driver_t* drv = &g_systick_driver; + + if (drv->cycles_per_us == 0) { + // The driver was not initialized yet - this could happen + // only if the function is called from the early initialization + // stage, before the `systick_init()` was called. In this case, + // we can't provide the correct value, so we return 0. + return 0; + } + + return systick_cycles() / drv->cycles_per_us; +} void SysTick_Handler(void) { SEGGER_SYSVIEW_RecordEnterISR(); - // this is a millisecond tick counter that wraps after approximately - // 49.71 days = (0xffffffff / (24 * 60 * 60 * 1000)) - uint32_t uw_tick = uwTick + 1; - uwTick = uw_tick; -#ifdef RDI - rdi_handler(uw_tick); -#endif + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + + systick_driver_t* drv = &g_systick_driver; + if (drv->initialized) { + // Increment `cycles` counter if COUNTFLAG is set. + // If COUNTFLAG is not set, `cycles` were already incremented + // in `systick_cycles()` that also cleared the COUNTFLAG. + if ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) != 0) { + // Clear COUNTFLAG by reading VAL + (void)SysTick->VAL; + // Increment cycles counter by SysTick period + drv->cycles += drv->cycles_per_ms; + // Increment regular ticks counter + drv->ticks++; + } + + // Invoke callbacks of expired timers + systimer_dispatch_expired_timers(drv->cycles); + } + + mpu_restore(mpu_mode); SEGGER_SYSVIEW_RecordExitISR(); } + +#endif // KERNEL_MODE + +void systick_delay_us(uint64_t us) { + uint64_t delay_cycles = systick_us_to_cycles(us); + int64_t cycles_per_ms = systick_us_to_cycles(1000); + + uint64_t end = systick_cycles() + delay_cycles; + bool irq_enabled = IS_IRQ_ENABLED(query_irq()); + int64_t diff; + + while ((diff = end - systick_cycles()) > 0) { + if (irq_enabled && (diff > cycles_per_ms)) { + // Enter sleep mode and wait for (at least) + // the SysTick interrupt. + __WFI(); + } + } +} + +void systick_delay_ms(uint32_t ms) { systick_delay_us((uint64_t)ms * 1000); } + +// We provide our own version of HAL_Delay that calls __WFI while waiting, +// and works when interrupts are disabled. This function is intended to be +// used only by the ST HAL functions. +void HAL_Delay(uint32_t ms) { systick_delay_ms(ms); } + +// We provide our own version of HAL_GetTick that replaces the default +// ST HAL function reading uwTick global variable. +uint32_t HAL_GetTick(void) { return systick_ms(); } diff --git a/core/embed/trezorhal/stm32f4/systick.h b/core/embed/trezorhal/stm32f4/systick.h deleted file mode 100644 index 7c94a91a3e3..00000000000 --- a/core/embed/trezorhal/stm32f4/systick.h +++ /dev/null @@ -1,37 +0,0 @@ -// clang-format off - -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2013, 2014 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef MICROPY_INCLUDED_STM32_SYSTICK_H -#define MICROPY_INCLUDED_STM32_SYSTICK_H - -#include -#include - -// Works for x between 0 and 16 inclusive -#define POW2_CEIL(x) ((((x) - 1) | ((x) - 1) >> 1 | ((x) - 1) >> 2 | ((x) - 1) >> 3) + 1) - -#endif // MICROPY_INCLUDED_STM32_SYSTICK_H diff --git a/core/embed/trezorhal/stm32f4/systick_internal.h b/core/embed/trezorhal/stm32f4/systick_internal.h new file mode 100644 index 00000000000..0f7a9a071ac --- /dev/null +++ b/core/embed/trezorhal/stm32f4/systick_internal.h @@ -0,0 +1,12 @@ +#ifndef TREZORHAL_SYSTICK_INTERNAL_H +#define TREZORHAL_SYSTICK_INTERNAL_H + +#include + +#include "systick.h" + +// Internal function called from interrupt context. +// Handles expired timers and invoked their callbacks. +void systimer_dispatch_expired_timers(uint64_t cycles); + +#endif // TREZORHAL_SYSTICK_INTERNAL_H diff --git a/core/embed/trezorhal/stm32f4/systimer.c b/core/embed/trezorhal/stm32f4/systimer.c new file mode 100644 index 00000000000..10736a5b771 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/systimer.c @@ -0,0 +1,241 @@ +/* + * 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 "irq.h" +#include "platform.h" +#include "systick_internal.h" +#include "systimer.h" + +#ifdef KERNEL_MODE + +// Maximum number of registered user timer +// +// Consider different implementation (i.e. priority queue +// using binary heap if MAX_SYSTIMERS exceeds 10 or more) +#define MAX_SYSTIMERS 8 + +// User timer instance +struct systimer { + // User callback function + // Non-NULL if the timer entry is valid + volatile systimer_callback_t callback; + // User callback context + void* context; + // Set if the timer is suspended + volatile bool suspended; + // Set if the timer is scheduled + volatile bool scheduled; + // Expiration time (valid if scheduled is set) + volatile uint64_t expiration; + // Period (= 0 for non-periodic timers) + volatile uint64_t period; +}; + +// systimer driver state +typedef struct { + // Set if the driver is initialized + bool initialized; + // Registered timers + // (unused slots have callback field set to NULL) + systimer_t timers[MAX_SYSTIMERS]; +} systimer_driver_t; + +static systimer_driver_t g_systimer_driver = { + .initialized = false, +}; + +void systimer_init(void) { + systimer_driver_t* drv = &g_systimer_driver; + + if (drv->initialized) { + return; + } + + memset(drv, 0, sizeof(systimer_driver_t)); + drv->initialized = true; +} + +void systimer_deinit(void) { + systimer_driver_t* drv = &g_systimer_driver; + + drv->initialized = false; +} + +static inline bool timer_valid(const systimer_driver_t* drv, + const systimer_t* timer) { + return drv->initialized && (timer >= &drv->timers[0]) && + (timer < &drv->timers[MAX_SYSTIMERS]); +} + +systimer_t* systimer_create(systimer_callback_t callback, void* context) { + systimer_driver_t* drv = &g_systimer_driver; + + if (!drv->initialized) { + return NULL; + } + + if (callback == NULL) { + // Since the callback is used to determine if the + // timer is valid, it must be non-NULL. + return NULL; + } + + irq_key_t irq_key = irq_lock(); + + // Find a free timer entry + for (int i = 0; i < MAX_SYSTIMERS; i++) { + systimer_t* timer = &drv->timers[i]; + + if (timer->callback == NULL) { + timer->scheduled = false; + timer->suspended = false; + timer->context = context; + timer->callback = callback; + + irq_unlock(irq_key); + return timer; + } + } + + // No free timer entry found + irq_unlock(irq_key); + return NULL; +} + +void systimer_delete(systimer_t* timer) { + systimer_driver_t* drv = &g_systimer_driver; + if (!timer_valid(drv, timer)) { + return; + } + + timer->callback = NULL; +} + +void systimer_set(systimer_t* timer, uint32_t delay_ms) { + systimer_driver_t* drv = &g_systimer_driver; + + if (!timer_valid(drv, timer)) { + return; + } + + uint64_t delay = systick_us_to_cycles((uint64_t)delay_ms * 1000); + uint64_t expiration = systick_cycles() + delay; + + irq_key_t irq_key = irq_lock(); + timer->expiration = expiration; + timer->period = 0; + timer->scheduled = true; + irq_unlock(irq_key); +} + +void systimer_set_periodic(systimer_t* timer, uint32_t period_ms) { + systimer_driver_t* drv = &g_systimer_driver; + + if (!timer_valid(drv, timer)) { + return; + } + + uint64_t period = systick_us_to_cycles((uint64_t)period_ms * 1000); + uint64_t expiration = systick_cycles() + period; + + irq_key_t irq_key = irq_lock(); + timer->expiration = expiration; + timer->period = period; + timer->scheduled = true; + irq_unlock(irq_key); +} + +bool systimer_unset(systimer_t* timer) { + systimer_driver_t* drv = &g_systimer_driver; + + if (!timer_valid(drv, timer)) { + return false; + } + + irq_key_t irq_key = irq_lock(); + bool was_scheduled = timer->scheduled; + timer->scheduled = false; + irq_unlock(irq_key); + return was_scheduled; +} + +systimer_key_t systimer_suspend(systimer_t* timer) { + systimer_driver_t* drv = &g_systimer_driver; + + if (!timer_valid(drv, timer)) { + return false; + } + + irq_key_t irq_key = irq_lock(); + bool was_suspended = timer->suspended; + timer->suspended = true; + irq_unlock(irq_key); + return was_suspended; +} + +void systimer_resume(systimer_t* timer, systimer_key_t key) { + systimer_driver_t* drv = &g_systimer_driver; + + if (!timer_valid(drv, timer)) { + return; + } + + timer->suspended = key; +} + +// Called from interrupt context +void systimer_dispatch_expired_timers(uint64_t cycles) { + systimer_driver_t* drv = &g_systimer_driver; + + if (!drv->initialized) { + return; + } + + // Go through all timer slots and invoke callbacks of expired timers + // This algorithm is not efficient for large number of timers + // but it is good enough if MAX_SYSTIMERS ~ 10 + + for (int i = 0; i < MAX_SYSTIMERS; i++) { + systimer_t* timer = &drv->timers[i]; + + if (timer->callback == NULL || timer->suspended || !timer->scheduled) { + continue; + } + + if (cycles < timer->expiration) { + continue; + } + + if (timer->period > 0) { + // Reschedule periodic timer + timer->expiration = cycles + timer->period; + } else { + // Stop one-shot timer + timer->scheduled = false; + } + + // Callback is invoked from interrupt context + timer->callback(timer->context); + } +} + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/touch/ft6x36.c b/core/embed/trezorhal/stm32f4/touch/ft6x36.c index 2d8e5485bf0..e107bbf8ab8 100644 --- a/core/embed/trezorhal/stm32f4/touch/ft6x36.c +++ b/core/embed/trezorhal/stm32f4/touch/ft6x36.c @@ -20,6 +20,8 @@ #include STM32_HAL_H #include TREZOR_BOARD +#ifdef KERNEL_MODE + #include #include #include @@ -27,7 +29,7 @@ #include "common.h" #include "ft6x36.h" -#include "i2c.h" +#include "i2c_bus.h" #include "touch.h" #ifdef TOUCH_PANEL_LX154A2422CPT23 @@ -40,6 +42,8 @@ typedef struct { // Set if the driver is initialized secbool initialized; + // I2c bus where the touch controller is connected + i2c_bus_t* i2c_bus; // Set if the driver is ready to report touches. // FT6X36 needs about 300ms after power-up to stabilize. secbool ready; @@ -71,30 +75,32 @@ static touch_driver_t g_touch_driver = { // // If the I2C bus is busy, the function will cycle the // bus and retry the operation. -static secbool ft6x36_read_regs(uint8_t reg, uint8_t* value, size_t count) { - uint16_t i2c_bus = TOUCH_I2C_INSTANCE; - uint8_t i2c_addr = FT6X36_I2C_ADDR; - uint8_t txdata[] = {reg}; - uint8_t retries = 3; - - do { - int result = i2c_transmit(i2c_bus, i2c_addr, txdata, sizeof(txdata), 10); - if (HAL_OK == result) { - result = i2c_receive(i2c_bus, i2c_addr, value, count, 10); - } +static secbool ft6x36_read_regs(i2c_bus_t* bus, uint8_t reg, uint8_t* value, + size_t count) { + i2c_op_t ops[] = { + { + .flags = I2C_FLAG_TX | I2C_FLAG_EMBED, + .size = 1, + .data = {reg}, + }, + { + .flags = I2C_FLAG_RX, + .size = count, + .ptr = value, + }, + }; - if (HAL_OK == result) { - // success - return sectrue; - } else if (HAL_BUSY == result && retries > 0) { - // I2C bus is busy, cycle it and try again - i2c_cycle(i2c_bus); - retries--; - } else { - // Aother error or retries exhausted - return secfalse; - } - } while (1); + i2c_packet_t pkt = { + .address = FT6X36_I2C_ADDR, + .op_count = ARRAY_LENGTH(ops), + .ops = ops, + }; + + if (I2C_STATUS_OK != i2c_bus_submit_and_wait(bus, &pkt)) { + return secfalse; + } + + return sectrue; } // Writes a register to the FT6X36. @@ -104,26 +110,26 @@ static secbool ft6x36_read_regs(uint8_t reg, uint8_t* value, size_t count) { // // If the I2C bus is busy, the function will cycle the // bus and retry the operation. -static secbool ft6x36_write_reg(uint8_t reg, uint8_t value) { - uint16_t i2c_bus = TOUCH_I2C_INSTANCE; - uint8_t i2c_addr = FT6X36_I2C_ADDR; - uint8_t txdata[] = {reg, value}; - uint8_t retries = 3; - - do { - int result = i2c_transmit(i2c_bus, i2c_addr, txdata, sizeof(txdata), 10); - if (HAL_OK == result) { - // success - return sectrue; - } else if (HAL_BUSY == result && retries > 0) { - // I2C bus is busy, cycle it and try again - i2c_cycle(i2c_bus); - retries--; - } else { - // Another error or retries exhausted - return secfalse; - } - } while (1); +static secbool ft6x36_write_reg(i2c_bus_t* bus, uint8_t reg, uint8_t value) { + i2c_op_t ops[] = { + { + .flags = I2C_FLAG_TX | I2C_FLAG_EMBED, + .size = 2, + .data = {reg, value}, + }, + }; + + i2c_packet_t pkt = { + .address = FT6X36_I2C_ADDR, + .op_count = ARRAY_LENGTH(ops), + .ops = ops, + }; + + if (I2C_STATUS_OK != i2c_bus_submit_and_wait(bus, &pkt)) { + return secfalse; + } + + return sectrue; } // Powers down the touch controller and puts all @@ -208,7 +214,7 @@ static bool ft6x36_test_and_clear_interrupt(void) { } // Configures the touch controller to the funtional state. -static secbool ft6x36_configure(void) { +static secbool ft6x36_configure(i2c_bus_t* i2c_bus) { const static uint8_t config[] = { // Set touch controller to the interrupt trigger mode. // Basically, CTPM generates a pulse when new data is available. @@ -224,7 +230,7 @@ static secbool ft6x36_configure(void) { uint8_t reg = config[i]; uint8_t value = config[i + 1]; - if (sectrue != ft6x36_write_reg(reg, value)) { + if (sectrue != ft6x36_write_reg(i2c_bus, reg, value)) { return secfalse; } } @@ -250,6 +256,8 @@ secbool touch_init(void) { return sectrue; } + memset(driver, 0, sizeof(touch_driver_t)); + // Initialize GPIO to the default configuration // (touch controller is powered down) ft6x36_power_down(); @@ -257,10 +265,14 @@ secbool touch_init(void) { // Power up the touch controller and perform the reset sequence ft6x36_power_up(); + driver->i2c_bus = i2c_bus_open(TOUCH_I2C_INSTANCE); + if (driver->i2c_bus == NULL) { + goto cleanup; + } + // Configure the touch controller - if (sectrue != ft6x36_configure()) { - ft6x36_power_down(); - return secfalse; + if (sectrue != ft6x36_configure(driver->i2c_bus)) { + goto cleanup; } driver->init_ticks = hal_ticks_ms(); @@ -269,16 +281,20 @@ secbool touch_init(void) { driver->initialized = sectrue; return sectrue; + +cleanup: + i2c_bus_close(driver->i2c_bus); + ft6x36_power_down(); + memset(driver, 0, sizeof(touch_driver_t)); + return secfalse; } void touch_deinit(void) { touch_driver_t* driver = &g_touch_driver; if (sectrue == driver->initialized) { - // Do not need to deinitialized the controller - // just power it off + i2c_bus_close(driver->i2c_bus); ft6x36_power_down(); - memset(driver, 0, sizeof(touch_driver_t)); } } @@ -301,7 +317,7 @@ secbool touch_set_sensitivity(uint8_t value) { touch_driver_t* driver = &g_touch_driver; if (sectrue == driver->initialized) { - return ft6x36_write_reg(FT6X36_REG_TH_GROUP, value); + return ft6x36_write_reg(driver->i2c_bus, FT6X36_REG_TH_GROUP, value); } else { return secfalse; } @@ -324,7 +340,8 @@ uint8_t touch_get_version(void) { uint8_t fw_version = 0; - if (sectrue != ft6x36_read_regs(FT6X36_REG_FIRMID, &fw_version, 1)) { + if (sectrue != + ft6x36_read_regs(driver->i2c_bus, FT6X36_REG_FIRMID, &fw_version, 1)) { ft6x36_power_down(); return secfalse; } @@ -432,7 +449,7 @@ uint32_t touch_get_event(void) { driver->read_ticks = ticks; // Read the set of registers containing touch event and coordinates - if (sectrue != ft6x36_read_regs(0x00, regs, sizeof(regs))) { + if (sectrue != ft6x36_read_regs(driver->i2c_bus, 0x00, regs, sizeof(regs))) { // Failed to read the touch registers return 0; } @@ -539,3 +556,5 @@ uint32_t touch_get_event(void) { return event; } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/touch/ft6x36.h b/core/embed/trezorhal/stm32f4/touch/ft6x36.h index 8629a126938..852b8fea391 100644 --- a/core/embed/trezorhal/stm32f4/touch/ft6x36.h +++ b/core/embed/trezorhal/stm32f4/touch/ft6x36.h @@ -21,8 +21,7 @@ #define _TOUCH_FT6X36_H // I2C address of the FT6X36 on the I2C bus. -// `<< 1` is required because the HAL expects the address to be shifted by 1. -#define FT6X36_I2C_ADDR (0x38 << 1) +#define FT6X36_I2C_ADDR 0x38 // ------------------------------------------------------------ // FT6X36 registers diff --git a/core/embed/trezorhal/stm32f4/touch/stmpe811.c b/core/embed/trezorhal/stm32f4/touch/stmpe811.c index 05a6f557271..3d3003999ad 100644 --- a/core/embed/trezorhal/stm32f4/touch/stmpe811.c +++ b/core/embed/trezorhal/stm32f4/touch/stmpe811.c @@ -20,12 +20,14 @@ #include STM32_HAL_H #include TREZOR_BOARD +#ifdef KERNEL_MODE + #include #include "common.h" #include "secbool.h" -#include "i2c.h" +#include "i2c_bus.h" #include "stmpe811.h" #include "touch.h" @@ -157,8 +159,6 @@ #define STMPE811_TS_CTRL_ENABLE 0x01 #define STMPE811_TS_CTRL_STATUS 0x80 -#define TOUCH_ADDRESS \ - (0x38U << 1) // the HAL requires the 7-bit address to be shifted by one bit #define TOUCH_PACKET_SIZE 7U #define EVENT_PRESS_DOWN 0x00U #define EVENT_CONTACT 0x80U @@ -173,17 +173,14 @@ #define EVENT_OLD_TIMEOUT_MS 50 #define EVENT_MISSING_TIMEOUT_MS 50 -#define TS_I2C_ADDRESS 0x82 +#define TS_I2C_ADDRESS (0x82 >> 1) #define I2Cx_TIMEOUT_MAX \ 0x3000 /*initialized != sectrue) { + i2c_bus = i2c_bus_open(TOUCH_I2C_INSTANCE); + if (i2c_bus == NULL) { + return secfalse; + } + stmpe811_Reset(); touch_set_mode(); @@ -589,6 +637,7 @@ void touch_deinit(void) { if (driver->initialized == sectrue) { // Not implemented properly + i2c_bus_close(i2c_bus); memset(driver, 0, sizeof(touch_driver_t)); } } @@ -644,3 +693,5 @@ uint32_t touch_get_event(void) { return event; } + +#endif diff --git a/core/embed/trezorhal/stm32f4/usb/usb.c b/core/embed/trezorhal/stm32f4/usb/usb.c index 7b0bd295e19..b4e7a974fdf 100644 --- a/core/embed/trezorhal/stm32f4/usb/usb.c +++ b/core/embed/trezorhal/stm32f4/usb/usb.c @@ -17,6 +17,8 @@ * along with this program. If not, see . */ +#ifdef KERNEL_MODE + #include STM32_HAL_H #include "usb.h" @@ -736,3 +738,5 @@ static const USBD_ClassTypeDef usb_class = { .GetDeviceQualifierDescriptor = NULL, .GetUsrStrDescriptor = usb_class_get_usrstr_desc, }; + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/usb/usb_class_hid.c b/core/embed/trezorhal/stm32f4/usb/usb_class_hid.c index 48feb58866f..67512153afb 100644 --- a/core/embed/trezorhal/stm32f4/usb/usb_class_hid.c +++ b/core/embed/trezorhal/stm32f4/usb/usb_class_hid.c @@ -17,6 +17,8 @@ * along with this program. If not, see . */ +#ifdef KERNEL_MODE + #include "common.h" #include "random_delays.h" @@ -444,3 +446,5 @@ static const USBD_ClassTypeDef usb_hid_class = { .GetDeviceQualifierDescriptor = NULL, .GetUsrStrDescriptor = NULL, }; + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/usb/usb_class_vcp.c b/core/embed/trezorhal/stm32f4/usb/usb_class_vcp.c index 7905d884f4b..4559fef33ba 100644 --- a/core/embed/trezorhal/stm32f4/usb/usb_class_vcp.c +++ b/core/embed/trezorhal/stm32f4/usb/usb_class_vcp.c @@ -17,6 +17,8 @@ * along with this program. If not, see . */ +#ifdef KERNEL_MODE + #include "common.h" #include "usb_internal.h" @@ -586,3 +588,5 @@ static const USBD_ClassTypeDef usb_vcp_class = { }; static const USBD_ClassTypeDef usb_vcp_data_class = {}; + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/usb/usb_class_webusb.c b/core/embed/trezorhal/stm32f4/usb/usb_class_webusb.c index 5d326517c32..8d9765829fe 100644 --- a/core/embed/trezorhal/stm32f4/usb/usb_class_webusb.c +++ b/core/embed/trezorhal/stm32f4/usb/usb_class_webusb.c @@ -17,6 +17,8 @@ * along with this program. If not, see . */ +#ifdef KERNEL_MODE + #include "common.h" #include "random_delays.h" @@ -354,3 +356,5 @@ static const USBD_ClassTypeDef usb_webusb_class = { .GetDeviceQualifierDescriptor = NULL, .GetUsrStrDescriptor = NULL, }; + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/usb/usbd_conf.c b/core/embed/trezorhal/stm32f4/usb/usbd_conf.c index 0434962d3a1..2db2a648843 100644 --- a/core/embed/trezorhal/stm32f4/usb/usbd_conf.c +++ b/core/embed/trezorhal/stm32f4/usb/usbd_conf.c @@ -50,12 +50,15 @@ * ****************************************************************************** */ + +#ifdef KERNEL_MODE + /* Includes ------------------------------------------------------------------*/ #include STM32_HAL_H #include "usbd_core.h" #include "usb.h" #include "irq.h" -#include "supervise.h" +#include "mpu.h" #include "systemview.h" /* Private typedef -----------------------------------------------------------*/ @@ -147,10 +150,10 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) #endif /* Set USBFS Interrupt priority */ - svc_setpriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS); + NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_NORMAL); /* Enable USBFS Interrupt */ - svc_enableIRQ(OTG_FS_IRQn); + NVIC_EnableIRQ(OTG_FS_IRQn); } #endif #if defined(USE_USB_HS) @@ -302,10 +305,10 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) #endif // !USE_USB_HS_IN_FS /* Set USBHS Interrupt to the lowest priority */ - svc_setpriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS); + NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_NORMAL); /* Enable USBHS Interrupt */ - svc_enableIRQ(OTG_HS_IRQn); + NVIC_EnableIRQ(OTG_HS_IRQn); } #endif // USE_USB_HS } @@ -797,9 +800,11 @@ void OTG_FS_IRQHandler(void) { #endif SEGGER_SYSVIEW_RecordEnterISR(); IRQ_ENTER(OTG_FS_IRQn); + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); if (pcd_fs_handle.Instance) { HAL_PCD_IRQHandler(&pcd_fs_handle); } + mpu_restore(mpu_mode); IRQ_EXIT(OTG_FS_IRQn); SEGGER_SYSVIEW_RecordExitISR(); } @@ -808,9 +813,11 @@ void OTG_FS_IRQHandler(void) { void OTG_HS_IRQHandler(void) { SEGGER_SYSVIEW_RecordEnterISR(); IRQ_ENTER(OTG_HS_IRQn); + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); if (pcd_hs_handle.Instance) { HAL_PCD_IRQHandler(&pcd_hs_handle); } + mpu_restore(mpu_mode); IRQ_EXIT(OTG_HS_IRQn); SEGGER_SYSVIEW_RecordExitISR(); } @@ -863,25 +870,31 @@ static void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) { #if defined(USE_USB_FS) void OTG_FS_WKUP_IRQHandler(void) { IRQ_ENTER(OTG_FS_WKUP_IRQn); + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); if (pcd_fs_handle.Instance) { OTG_CMD_WKUP_Handler(&pcd_fs_handle); } /* Clear EXTI pending Bit*/ __HAL_USB_OTG_FS_WAKEUP_EXTI_CLEAR_FLAG(); + mpu_restore(mpu_mode); IRQ_EXIT(OTG_FS_WKUP_IRQn); } #endif #if defined(USE_USB_HS) void OTG_HS_WKUP_IRQHandler(void) { IRQ_ENTER(OTG_HS_WKUP_IRQn); + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); if (pcd_hs_handle.Instance) { OTG_CMD_WKUP_Handler(&pcd_hs_handle); } /* Clear EXTI pending Bit*/ __HAL_USB_HS_EXTI_CLEAR_FLAG(); + mpu_restore(mpu_mode); IRQ_EXIT(OTG_HS_WKUP_IRQn); } #endif #endif +#endif // KERNEL_MODE + /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/core/embed/trezorhal/stm32f4/usb/usbd_core.c b/core/embed/trezorhal/stm32f4/usb/usbd_core.c index 2663a6d88c3..5188125601d 100644 --- a/core/embed/trezorhal/stm32f4/usb/usbd_core.c +++ b/core/embed/trezorhal/stm32f4/usb/usbd_core.c @@ -27,6 +27,8 @@ ****************************************************************************** */ +#ifdef KERNEL_MODE + /* Includes ------------------------------------------------------------------*/ #include "usbd_core.h" @@ -576,5 +578,7 @@ USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev) * @} */ +#endif // KERNEL_MODE + /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/core/embed/trezorhal/stm32f4/usb/usbd_ctlreq.c b/core/embed/trezorhal/stm32f4/usb/usbd_ctlreq.c index 31c97e5f635..6b4d2177c88 100644 --- a/core/embed/trezorhal/stm32f4/usb/usbd_ctlreq.c +++ b/core/embed/trezorhal/stm32f4/usb/usbd_ctlreq.c @@ -27,6 +27,8 @@ ****************************************************************************** */ +#ifdef KERNEL_MODE + /* Includes ------------------------------------------------------------------*/ #include "usbd_ctlreq.h" #include "usbd_ioreq.h" @@ -784,4 +786,6 @@ static uint8_t USBD_GetLen(const uint8_t *buf) * @} */ +#endif // KERNEL_MODE + /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/core/embed/trezorhal/stm32f4/usb/usbd_ioreq.c b/core/embed/trezorhal/stm32f4/usb/usbd_ioreq.c index ebbdd3b1520..c22e0eef62b 100644 --- a/core/embed/trezorhal/stm32f4/usb/usbd_ioreq.c +++ b/core/embed/trezorhal/stm32f4/usb/usbd_ioreq.c @@ -27,6 +27,8 @@ ****************************************************************************** */ +#ifdef KERNEL_MODE + /* Includes ------------------------------------------------------------------*/ #include "usbd_ioreq.h" @@ -235,4 +237,6 @@ uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , uint8_t ep_addr) * @} */ +#endif // KERNEL_MODE + /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/core/embed/trezorhal/stm32f4/util.s b/core/embed/trezorhal/stm32f4/util.S similarity index 82% rename from core/embed/trezorhal/stm32f4/util.s rename to core/embed/trezorhal/stm32f4/util.S index defc3c70f96..b01f5ee1a07 100644 --- a/core/embed/trezorhal/stm32f4/util.s +++ b/core/embed/trezorhal/stm32f4/util.S @@ -2,6 +2,8 @@ .text +#ifdef KERNEL_MODE + .global memset_reg .type memset_reg, STT_FUNC memset_reg: @@ -10,10 +12,13 @@ memset_reg: // 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 @@ -42,13 +47,12 @@ jump_to_with_flag: cpsid f // wipe memory at the end of the current stage of code bl clear_otg_hs_memory - ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =boot_args_start // r1 - point to byte after the end of CCMRAM - ldr r2, =0 // r2 - the word-sized value to be written + ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_handoff_clear_ram_0_start + ldr r1, =_handoff_clear_ram_0_end bl memset_reg - ldr r0, =sram_start // r0 - point to beginning of SRAM - ldr r1, =sram_end // r1 - point to byte after the end of SRAM - ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_handoff_clear_ram_1_start + ldr r1, =_handoff_clear_ram_1_end bl memset_reg mov lr, r4 // clear out the general purpose registers before the next stage's except the register with flag R11 @@ -98,13 +102,12 @@ shutdown_privileged: mov r11, r0 mov r12, r0 ldr lr, =0xffffffff - ldr r0, =ccmram_start - ldr r1, =ccmram_end - // set to value in r2 + + ldr r0, =_shutdown_clear_ram_0_start + ldr r1, =_shutdown_clear_ram_0_end bl memset_reg - ldr r0, =sram_start - ldr r1, =sram_end - // set to value in r2 + ldr r0, =_shutdown_clear_ram_1_start + ldr r1, =_shutdown_clear_ram_1_end bl memset_reg bl clear_otg_hs_memory ldr r0, =1 @@ -112,16 +115,6 @@ 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 +#endif .end diff --git a/core/embed/trezorhal/stm32f4/vectortable.s b/core/embed/trezorhal/stm32f4/vectortable.S similarity index 96% rename from core/embed/trezorhal/stm32f4/vectortable.s rename to core/embed/trezorhal/stm32f4/vectortable.S index 08b34f99f8f..2f07d34fd11 100644 --- a/core/embed/trezorhal/stm32f4/vectortable.s +++ b/core/embed/trezorhal/stm32f4/vectortable.S @@ -2,6 +2,8 @@ .text +#ifdef KERNEL_MODE + .global default_handler .type default_handler, STT_FUNC default_handler: @@ -126,4 +128,15 @@ vector_table: add_handler LTDC_ER_IRQHandler add_handler DMA2D_IRQHandler +#else + + .section .vector_table, "a" +vector_table: + .word _sstack + .word _stack_size + .word reset_handler + + +#endif + .end diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_driver.c b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_driver.c index e486ebfaf3d..d08911ae8c0 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_driver.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_driver.c @@ -27,7 +27,6 @@ #include "display_panel.h" #include "backlight_pwm.h" -#include "supervise.h" #ifndef BOARDLOADER #include "bg_copy.h" @@ -40,56 +39,91 @@ #error "Incompatible display resolution" #endif +#ifdef KERNEL_MODE + // Display driver instance -display_driver_t g_display_driver; +display_driver_t g_display_driver = { + .initialized = false, +}; -void display_init(void) { +void display_init(display_content_mode_t mode) { display_driver_t* drv = &g_display_driver; + + if (drv->initialized) { + return; + } + memset(drv, 0, sizeof(display_driver_t)); - display_io_init_gpio(); - display_io_init_fmc(); - display_panel_init(); - display_panel_set_little_endian(); - backlight_pwm_init(BACKLIGHT_RESET); + if (mode == DISPLAY_RESET_CONTENT) { + display_io_init_gpio(); + display_io_init_fmc(); + display_panel_init(); + display_panel_set_little_endian(); + backlight_pwm_init(BACKLIGHT_RESET); + } else { + // Reinitialize FMC to set correct timing + // We have to do this in reinit because boardloader is fixed. + display_io_init_fmc(); + + // Important for model T as this is not set in boardloader + display_panel_set_little_endian(); + display_panel_reinit(); + backlight_pwm_init(BACKLIGHT_RETAIN); + } #ifdef XFRAMEBUFFER +#ifndef BOARDLOADER display_io_init_te_interrupt(); #endif +#endif + + drv->initialized = true; } -void display_reinit(void) { +void display_deinit(display_content_mode_t mode) { display_driver_t* drv = &g_display_driver; - memset(drv, 0, sizeof(display_driver_t)); - - // Reinitialize FMC to set correct timing - // We have to do this in reinit because boardloader is fixed. - display_io_init_fmc(); - // Important for model T as this is not set in boardloader - display_panel_set_little_endian(); - display_panel_reinit(); - backlight_pwm_init(BACKLIGHT_RETAIN); - -#ifdef XFRAMEBUFFER - display_io_init_te_interrupt(); -#endif -} + if (!drv->initialized) { + return; + } -void display_finish_actions(void) { #ifdef XFRAMEBUFFER #ifndef BOARDLOADER + // Ensure that the ready frame buffer is transfered to + // the display controller display_ensure_refreshed(); - svc_disableIRQ(DISPLAY_TE_INTERRUPT_NUM); + // Disable periodical interrupt + NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); #endif #endif + + backlight_pwm_deinit(mode == DISPLAY_RESET_CONTENT ? BACKLIGHT_RESET + : BACKLIGHT_RETAIN); + +#ifdef TREZOR_MODEL_T + // This ensures backward compatibility with legacy bootloader/firmware + // that relies on this hardware settings from the previous boot stage + if (mode == DISPLAY_RESET_CONTENT) { + display_set_orientation(0); + } + display_panel_set_big_endian(); +#endif + + drv->initialized = false; } int display_set_backlight(int level) { + display_driver_t* drv = &g_display_driver; + + if (!drv->initialized) { + return 0; + } + #ifdef XFRAMEBUFFER #ifndef BOARDLOADER // if turning on the backlight, wait until the panel is refreshed - if (backlight_pwm_get() < level && !is_mode_handler()) { + if (backlight_pwm_get() < level && !is_mode_exception()) { display_ensure_refreshed(); } #endif @@ -103,6 +137,10 @@ int display_get_backlight(void) { return backlight_pwm_get(); } int display_set_orientation(int angle) { display_driver_t* drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + if (angle != drv->orientation_angle) { if (angle == 0 || angle == 90 || angle == 180 || angle == 270) { drv->orientation_angle = angle; @@ -128,7 +166,11 @@ int display_set_orientation(int angle) { int display_get_orientation(void) { display_driver_t* drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + return drv->orientation_angle; } -void display_set_compatible_settings(void) { display_panel_set_big_endian(); } +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.c b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.c index a0e89d1bd22..412e359f171 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.c @@ -32,7 +32,7 @@ #include "gfx_bitblt.h" #include "irq.h" -#include "supervise.h" +#include "mpu.h" #ifndef BOARDLOADER #include "bg_copy.h" @@ -42,6 +42,8 @@ #error Framebuffer only supported on STM32U5 for now #endif +#ifdef KERNEL_MODE + // The following code supports only 1 or 2 frame buffers _Static_assert(FRAME_BUFFER_COUNT == 1 || FRAME_BUFFER_COUNT == 2); @@ -96,7 +98,7 @@ static void bg_copy_callback(void) { } // Interrupt routing handling TE signal -void DISPLAY_TE_INTERRUPT_HANDLER(void) { +static void display_te_interrupt_handler(void) { display_driver_t *drv = &g_display_driver; __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); @@ -134,11 +136,25 @@ void DISPLAY_TE_INTERRUPT_HANDLER(void) { break; } } + +void DISPLAY_TE_INTERRUPT_HANDLER(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + display_te_interrupt_handler(); + mpu_restore(mpu_mode); +} #endif display_fb_info_t display_get_frame_buffer(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + display_fb_info_t fb = { + .ptr = NULL, + .stride = 0, + }; + return fb; + } + frame_buffer_state_t state; // We have to wait if the buffer was passed for copying @@ -191,6 +207,10 @@ static void wait_for_te_signal(void) { void display_refresh(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + if (drv->queue.entry[drv->queue.wix] != FB_STATE_PREPARING) { // No refresh needed as the frame buffer is not in // the state to be copied to the display @@ -198,9 +218,9 @@ void display_refresh(void) { } #ifndef BOARDLOADER - if (is_mode_handler()) { + if (is_mode_exception()) { // Disable scheduling of any new background copying - HAL_NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); + NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); // Wait for next TE signal. During this time the // display might be updated in the background wait_for_te_signal(); @@ -216,7 +236,7 @@ void display_refresh(void) { drv->queue.entry[i] = FB_STATE_EMPTY; } // Enable normal processing again - HAL_NVIC_EnableIRQ(DISPLAY_TE_INTERRUPT_NUM); + NVIC_EnableIRQ(DISPLAY_TE_INTERRUPT_NUM); } else { // Mark the buffer ready to switch to drv->queue.entry[drv->queue.wix] = FB_STATE_READY; @@ -234,7 +254,11 @@ void display_ensure_refreshed(void) { #ifndef BOARDLOADER display_driver_t *drv = &g_display_driver; - if (!is_mode_handler()) { + if (!drv->initialized) { + return; + } + + if (!is_mode_exception()) { bool copy_pending; // Wait until all frame buffers are written to the display @@ -265,6 +289,10 @@ void display_ensure_refreshed(void) { void display_fill(const gfx_bitblt_t *bb) { display_fb_info_t fb = display_get_frame_buffer(); + if (fb.ptr == NULL) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint16_t *)((uintptr_t)fb.ptr + fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; @@ -275,6 +303,10 @@ void display_fill(const gfx_bitblt_t *bb) { void display_copy_rgb565(const gfx_bitblt_t *bb) { display_fb_info_t fb = display_get_frame_buffer(); + if (fb.ptr == NULL) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint16_t *)((uintptr_t)fb.ptr + fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; @@ -285,6 +317,10 @@ void display_copy_rgb565(const gfx_bitblt_t *bb) { void display_copy_mono1p(const gfx_bitblt_t *bb) { display_fb_info_t fb = display_get_frame_buffer(); + if (fb.ptr == NULL) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint16_t *)((uintptr_t)fb.ptr + fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; @@ -295,9 +331,15 @@ void display_copy_mono1p(const gfx_bitblt_t *bb) { void display_copy_mono4(const gfx_bitblt_t *bb) { display_fb_info_t fb = display_get_frame_buffer(); + if (fb.ptr == NULL) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint16_t *)((uintptr_t)fb.ptr + fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; gfx_rgb565_copy_mono4(&bb_new); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_internal.h b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_internal.h index 611e02e0c93..4bcad64c8c4 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_internal.h +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_internal.h @@ -41,6 +41,9 @@ typedef struct { // Display driver state typedef struct { + // Set if the driver is initialized + bool initialized; + #ifdef XFRAMEBUFFER // Framebuffer queue // (accessed & updated in the context of the main thread @@ -56,4 +59,9 @@ typedef struct { // Display driver instance extern display_driver_t g_display_driver; +static inline uint32_t is_mode_exception(void) { + uint32_t isr_number = __get_IPSR() & IPSR_ISR_Msk; + return (isr_number > 0) && (isr_number << 11); +} + #endif // TREZORHAL_DISPLAY_INTERNAL_H diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c index edb12ef49c3..5f237af58da 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c @@ -22,7 +22,7 @@ #include "display_io.h" #include "irq.h" -#include "supervise.h" +#include "mpu.h" __IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS = (__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE); @@ -30,6 +30,8 @@ __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS = (__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE | (DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN)); +#ifdef KERNEL_MODE + void display_io_init_gpio(void) { // init peripherals __HAL_RCC_GPIOE_CLK_ENABLE(); @@ -128,7 +130,9 @@ void display_io_init_fmc(void) { normal_mode_timing.DataLatency = 2; // don't care normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A; + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_FSMC_REGS); HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL); + mpu_restore(mpu_mode); } #ifdef DISPLAY_TE_INTERRUPT_HANDLER @@ -142,7 +146,9 @@ void display_io_init_te_interrupt(void) { HAL_EXTI_SetConfigLine(&EXTI_Handle, &EXTI_Config); // setup interrupt for tearing effect pin - HAL_NVIC_SetPriority(DISPLAY_TE_INTERRUPT_NUM, IRQ_PRI_DMA, 0); - svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM); + NVIC_SetPriority(DISPLAY_TE_INTERRUPT_NUM, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(DISPLAY_TE_INTERRUPT_NUM); } #endif + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_nofb.c b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_nofb.c index 412427a0b94..83eba001c84 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_nofb.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_nofb.c @@ -24,6 +24,8 @@ #include "display_io.h" #include "display_panel.h" +#ifdef KERNEL_MODE + void display_refresh(void) { // If the framebuffer is not used the, we do not need // to refresh the display explicitly as we write the data @@ -118,3 +120,5 @@ void display_copy_mono4(const gfx_bitblt_t* bb) { src_row += bb->src_stride / sizeof(*src_row); } } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_panel.c b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_panel.c index 0d9bcf41519..bfe04057024 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_panel.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_panel.c @@ -34,6 +34,8 @@ #include "panels/lx154a2482.h" #endif +#ifdef KERNEL_MODE + // using const volatile instead of #define results in binaries that change // only in 1-byte when the flag changes. // using #define leads compiler to over-optimize the code leading to bigger @@ -248,3 +250,5 @@ void display_panel_rotate(int angle) { lx154a2482_rotate(angle, &g_window_padding); #endif } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/xdisplay/stm32f429i-disc1/display_driver.c b/core/embed/trezorhal/stm32f4/xdisplay/stm32f429i-disc1/display_driver.c index 378e63f7002..1198f897b84 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/stm32f429i-disc1/display_driver.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/stm32f429i-disc1/display_driver.c @@ -23,6 +23,8 @@ #include TREZOR_BOARD #include STM32_HAL_H +#ifdef KERNEL_MODE + #include "display_internal.h" #include "ili9341_spi.h" #include "xdisplay.h" @@ -33,6 +35,8 @@ // Display driver context. typedef struct { + // Set if the driver is initialized + bool initialized; // Pointer to the frame buffer uint16_t *framebuf; // Current display orientation (0, 90, 180, 270) @@ -42,32 +46,43 @@ typedef struct { } display_driver_t; // Display driver instance -static display_driver_t g_display_driver; +static display_driver_t g_display_driver = { + .initialized = false, +}; -void display_init(void) { +void display_init(display_content_mode_t mode) { display_driver_t *drv = &g_display_driver; + + if (drv->initialized) { + return; + } + memset(drv, 0, sizeof(display_driver_t)); drv->framebuf = (uint16_t *)FRAME_BUFFER_ADDR; - // Initialize LTDC controller - BSP_LCD_Init(); - // Initialize external display controller - ili9341_init(); + if (mode == DISPLAY_RESET_CONTENT) { + // Initialize LTDC controller + BSP_LCD_Init(); + // Initialize external display controller + ili9341_init(); + } + + drv->initialized = true; } -void display_reinit(void) { +void display_deinit(display_content_mode_t mode) { display_driver_t *drv = &g_display_driver; - memset(drv, 0, sizeof(display_driver_t)); - drv->framebuf = (uint16_t *)FRAME_BUFFER_ADDR; -} -void display_finish_actions(void) { - // Not used and intentionally left empty + drv->initialized = false; } int display_set_backlight(int level) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + // Just emulation, not doing anything drv->backlight_level = level; return level; @@ -76,12 +91,20 @@ int display_set_backlight(int level) { int display_get_backlight(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + return drv->backlight_level; } int display_set_orientation(int angle) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + if (angle == 0 || angle == 90 || angle == 180 || angle == 270) { // Just emulation, not doing anything drv->orientation_angle = angle; @@ -93,29 +116,42 @@ int display_set_orientation(int angle) { int display_get_orientation(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + return drv->orientation_angle; } display_fb_info_t display_get_frame_buffer(void) { display_driver_t *drv = &g_display_driver; - display_fb_info_t fb = { - .ptr = (void *)drv->framebuf, - .stride = DISPLAY_RESX * sizeof(uint16_t), - }; - - return fb; + if (!drv->initialized) { + display_fb_info_t fb = { + .ptr = NULL, + .stride = 0, + }; + return fb; + } else { + display_fb_info_t fb = { + .ptr = (void *)drv->framebuf, + .stride = DISPLAY_RESX * sizeof(uint16_t), + }; + return fb; + } } void display_refresh(void) { // Do nothing as using just a single frame buffer } -void display_set_compatible_settings() {} - void display_fill(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y); bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t); @@ -126,6 +162,10 @@ void display_fill(const gfx_bitblt_t *bb) { void display_copy_rgb565(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y); bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t); @@ -136,6 +176,10 @@ void display_copy_rgb565(const gfx_bitblt_t *bb) { void display_copy_mono1p(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y); bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t); @@ -146,9 +190,15 @@ void display_copy_mono1p(const gfx_bitblt_t *bb) { void display_copy_mono4(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y); bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t); gfx_rgb565_copy_mono4(&bb_new); } + +#endif diff --git a/core/embed/trezorhal/stm32f4/xdisplay/ug-2828/display_driver.c b/core/embed/trezorhal/stm32f4/xdisplay/ug-2828/display_driver.c index 7c2363713c9..dfdf9041c8d 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/ug-2828/display_driver.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/ug-2828/display_driver.c @@ -37,6 +37,8 @@ // Display driver context. typedef struct { + // Set if the driver is initialized + bool initialized; // Frame buffer (8-bit Mono) uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY]; // Current display orientation (0 or 180) @@ -46,7 +48,9 @@ typedef struct { } display_driver_t; // Display driver instance -static display_driver_t g_display_driver; +static display_driver_t g_display_driver = { + .initialized = false, +}; // Macros to access display parallel interface @@ -179,6 +183,10 @@ static void display_set_page_and_col(uint8_t page, uint8_t col) { static void display_sync_with_fb(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return NULL; + } + for (int y = 0; y < DISPLAY_RESY / 8; y++) { display_set_page_and_col(y, 0); uint8_t *src = &drv->framebuf[y * DISPLAY_RESX * 8]; @@ -291,30 +299,38 @@ static void display_init_interface(void) { HAL_SRAM_Init(&display_sram, &normal_mode_timing, NULL); } -void display_init(void) { +void display_init(display_content_mode_t mode) { display_driver_t *drv = &g_display_driver; - memset(drv, 0, sizeof(display_driver_t)); - // Initialize GPIO & FSMC controller - display_init_interface(); - // Initialize display controller - display_init_controller(); -} + if (drv->initialized) { + return; + } -void display_reinit(void) { - display_driver_t *drv = &g_display_driver; memset(drv, 0, sizeof(display_driver_t)); - // !@# TODO backlight level?? + if (mode == DISPLAY_RESET_CONTENT) { + // Initialize GPIO & FSMC controller + display_init_interface(); + // Initialize display controller + display_init_controller(); + } + + drv->initialized = true; } -void display_finish_actions(void) { - /// Not used and intentionally left empty +void display_deinit(display_content_mode_t mode) { + display_driver_t *drv = &g_display_driver; + + drv->initialized = false; } int display_set_backlight(int level) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + if (level != drv->backlight_level) { if (level >= 0 && level <= 255) { drv->backlight_level = level; @@ -330,12 +346,20 @@ int display_set_backlight(int level) { int display_get_backlight(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + return drv->backlight_level; } int display_set_orientation(int angle) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + if (angle != drv->orientation_angle) { if (angle == 0 || angle == 180) { drv->orientation_angle = angle; @@ -359,27 +383,48 @@ int display_set_orientation(int angle) { int display_get_orientation(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + return drv->orientation_angle; } display_fb_info_t display_get_frame_buffer(void) { display_driver_t *drv = &g_display_driver; - display_fb_info_t fb = { - .ptr = &drv->framebuf[0], - .stride = DISPLAY_RESX, - }; - - return fb; + if (!drv->initialized) { + const static display_fb_info_t fb = { + .ptr = NULL, + .stride = 0, + }; + return fb; + } else { + display_fb_info_t fb = { + .ptr = &drv->framebuf[0], + .stride = DISPLAY_RESX, + }; + return fb; + } } -void display_refresh(void) { display_sync_with_fb(); } +void display_refresh(void) { + display_driver_t *drv = &g_display_driver; + + if (!drv->initialized) { + return NULL; + } -void display_set_compatible_settings() {} + display_sync_with_fb(); +} void display_fill(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return NULL; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = &drv->framebuf[DISPLAY_RESX * bb_new.dst_y]; bb_new.dst_stride = DISPLAY_RESX; @@ -390,6 +435,10 @@ void display_fill(const gfx_bitblt_t *bb) { void display_copy_mono1p(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return NULL; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = &drv->framebuf[DISPLAY_RESX * bb_new.dst_y]; bb_new.dst_stride = DISPLAY_RESX; diff --git a/core/embed/trezorhal/stm32f4/xdisplay/vg-2864/display_driver.c b/core/embed/trezorhal/stm32f4/xdisplay/vg-2864/display_driver.c index c0860a2c33c..bdcf47157b0 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/vg-2864/display_driver.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/vg-2864/display_driver.c @@ -31,6 +31,7 @@ #include "consumption_mask.h" #endif +#ifdef KERNEL_MODE #if (DISPLAY_RESX != 128) || (DISPLAY_RESY != 64) #error "Incompatible display resolution" #endif @@ -38,14 +39,18 @@ // This file implements display driver for monochromatic display V-2864KSWEG01 // with 128x64 resolution connected to CPU via SPI interface. // -// This type of display is used with T3T1 model (Trezor TS3) +// This type of display is used with T3B1 model (Trezor TS3) + +__attribute__((section(".fb1"))) uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY]; // Display driver context. typedef struct { + // Set if the driver is initialized + bool initialized; // SPI driver instance SPI_HandleTypeDef spi; // Frame buffer (8-bit Mono) - uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY]; + uint8_t *framebuf; // Current display orientation (0 or 180) int orientation_angle; // Current backlight level ranging from 0 to 255 @@ -53,7 +58,9 @@ typedef struct { } display_driver_t; // Display driver instance -static display_driver_t g_display_driver; +static display_driver_t g_display_driver = { + .initialized = false, +}; // Display controller registers #define OLED_SETCONTRAST 0x81 @@ -220,89 +227,97 @@ static void display_sync_with_fb(display_driver_t *drv) { HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); } -void display_init(void) { +void display_init(display_content_mode_t mode) { display_driver_t *drv = &g_display_driver; + if (drv->initialized) { + return; + } + memset(drv, 0, sizeof(display_driver_t)); drv->backlight_level = 255; + drv->framebuf = framebuf; + + if (mode == DISPLAY_RESET_CONTENT) { + OLED_DC_CLK_ENA(); + OLED_CS_CLK_ENA(); + OLED_RST_CLK_ENA(); + OLED_SPI_SCK_CLK_ENA(); + OLED_SPI_MOSI_CLK_ENA(); + OLED_SPI_CLK_ENA(); + + GPIO_InitTypeDef GPIO_InitStructure; + + // Set GPIO for OLED display + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = 0; + GPIO_InitStructure.Pin = OLED_CS_PIN; + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); + HAL_GPIO_Init(OLED_CS_PORT, &GPIO_InitStructure); + GPIO_InitStructure.Pin = OLED_DC_PIN; + HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); + HAL_GPIO_Init(OLED_DC_PORT, &GPIO_InitStructure); + GPIO_InitStructure.Pin = OLED_RST_PIN; + HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET); + HAL_GPIO_Init(OLED_RST_PORT, &GPIO_InitStructure); + + // Enable SPI 1 for OLED display + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = OLED_SPI_AF; + GPIO_InitStructure.Pin = OLED_SPI_SCK_PIN; + HAL_GPIO_Init(OLED_SPI_SCK_PORT, &GPIO_InitStructure); + GPIO_InitStructure.Pin = OLED_SPI_MOSI_PIN; + HAL_GPIO_Init(OLED_SPI_MOSI_PORT, &GPIO_InitStructure); + + // Initialize SPI controller + display_init_spi(drv); + + // Set to CMD + HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); + // SPI deselect + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); + + // Reset the LCD + HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET); + HAL_Delay(1); + HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET); + HAL_Delay(1); + HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET); + + // SPI select + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); + // Send initialization command sequence + display_send_bytes(drv, &vg_2864ksweg01_init_seq[0], + sizeof(vg_2864ksweg01_init_seq)); + // SPI deselect + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); + + // Clear display internal framebuffer + display_sync_with_fb(drv); + } else { + display_init_spi(drv); + } - OLED_DC_CLK_ENA(); - OLED_CS_CLK_ENA(); - OLED_RST_CLK_ENA(); - OLED_SPI_SCK_CLK_ENA(); - OLED_SPI_MOSI_CLK_ENA(); - OLED_SPI_CLK_ENA(); - - GPIO_InitTypeDef GPIO_InitStructure; - - // Set GPIO for OLED display - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStructure.Alternate = 0; - GPIO_InitStructure.Pin = OLED_CS_PIN; - HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); - HAL_GPIO_Init(OLED_CS_PORT, &GPIO_InitStructure); - GPIO_InitStructure.Pin = OLED_DC_PIN; - HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); - HAL_GPIO_Init(OLED_DC_PORT, &GPIO_InitStructure); - GPIO_InitStructure.Pin = OLED_RST_PIN; - HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET); - HAL_GPIO_Init(OLED_RST_PORT, &GPIO_InitStructure); - - // Enable SPI 1 for OLED display - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStructure.Alternate = OLED_SPI_AF; - GPIO_InitStructure.Pin = OLED_SPI_SCK_PIN; - HAL_GPIO_Init(OLED_SPI_SCK_PORT, &GPIO_InitStructure); - GPIO_InitStructure.Pin = OLED_SPI_MOSI_PIN; - HAL_GPIO_Init(OLED_SPI_MOSI_PORT, &GPIO_InitStructure); - - // Initialize SPI controller - display_init_spi(drv); - - // Set to CMD - HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); - // SPI deselect - HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); - - // Reset the LCD - HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET); - HAL_Delay(1); - HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET); - HAL_Delay(1); - HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET); - - // SPI select - HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); - // Send initialization command sequence - display_send_bytes(drv, &vg_2864ksweg01_init_seq[0], - sizeof(vg_2864ksweg01_init_seq)); - // SPI deselect - HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); - - // Clear display internal framebuffer - display_sync_with_fb(drv); + drv->initialized = true; } -void display_reinit(void) { +void display_deinit(display_content_mode_t mode) { display_driver_t *drv = &g_display_driver; - memset(drv, 0, sizeof(display_driver_t)); - drv->backlight_level = 255; - - display_init_spi(drv); -} - -void display_finish_actions(void) { - /// Not used and intentionally left empty + drv->initialized = false; } int display_set_backlight(int level) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + drv->backlight_level = 255; return drv->backlight_level; } @@ -310,12 +325,20 @@ int display_set_backlight(int level) { int display_get_backlight(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + return drv->backlight_level; } int display_set_orientation(int angle) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + if (angle != drv->orientation_angle) { if (angle == 0 || angle == 180) { drv->orientation_angle = angle; @@ -329,23 +352,38 @@ int display_set_orientation(int angle) { int display_get_orientation(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + return drv->orientation_angle; } display_fb_info_t display_get_frame_buffer(void) { display_driver_t *drv = &g_display_driver; - display_fb_info_t fb = { - .ptr = &drv->framebuf[0], - .stride = DISPLAY_RESX, - }; - - return fb; + if (!drv->initialized) { + static const display_fb_info_t fb = { + .ptr = NULL, + .stride = 0, + }; + return fb; + } else { + display_fb_info_t fb = { + .ptr = &drv->framebuf[0], + .stride = DISPLAY_RESX, + }; + return fb; + } } void display_refresh(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + #if defined USE_CONSUMPTION_MASK && !defined BOARDLOADER // This is an intentional randomization of the consumption masking algorithm // after every change on the display @@ -356,24 +394,32 @@ void display_refresh(void) { display_sync_with_fb(drv); } -void display_set_compatible_settings() {} - void display_fill(const gfx_bitblt_t *bb) { - display_driver_t *drv = &g_display_driver; + display_fb_info_t fb = display_get_frame_buffer(); + + if (fb.ptr == NULL) { + return; + } gfx_bitblt_t bb_new = *bb; - bb_new.dst_row = &drv->framebuf[DISPLAY_RESX * bb_new.dst_y]; + bb_new.dst_row = &(((uint8_t *)fb.ptr)[DISPLAY_RESX * bb_new.dst_y]); bb_new.dst_stride = DISPLAY_RESX; gfx_mono8_fill(&bb_new); } void display_copy_mono1p(const gfx_bitblt_t *bb) { - display_driver_t *drv = &g_display_driver; + display_fb_info_t fb = display_get_frame_buffer(); + + if (fb.ptr == NULL) { + return; + } gfx_bitblt_t bb_new = *bb; - bb_new.dst_row = &drv->framebuf[DISPLAY_RESX * bb_new.dst_y]; + bb_new.dst_row = &(((uint8_t *)fb.ptr)[DISPLAY_RESX * bb_new.dst_y]); bb_new.dst_stride = DISPLAY_RESX; gfx_mono8_copy_mono1p(&bb_new); } + +#endif diff --git a/core/embed/trezorhal/stm32u5/applet.c b/core/embed/trezorhal/stm32u5/applet.c new file mode 120000 index 00000000000..0cdabf36aa6 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/applet.c @@ -0,0 +1 @@ +../stm32f4/applet.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/bg_copy.c b/core/embed/trezorhal/stm32u5/bg_copy.c index 97c2b6b66e9..ba54494bf6c 100644 --- a/core/embed/trezorhal/stm32u5/bg_copy.c +++ b/core/embed/trezorhal/stm32u5/bg_copy.c @@ -1,8 +1,11 @@ #include "bg_copy.h" #include "irq.h" +#include "mpu.h" #include STM32_HAL_H +#ifdef KERNEL_MODE + #define MAX_DATA_SIZE 0xFFF0 static volatile uint32_t dma_transfer_remaining = 0; @@ -33,6 +36,8 @@ void HAL_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma) { } void GPDMA1_Channel0_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + if ((DMA_Handle.Instance->CSR & DMA_CSR_TCF) == 0) { // error, abort the transfer and allow the next one to start dma_data_transferred = 0; @@ -44,7 +49,8 @@ void GPDMA1_Channel0_IRQHandler(void) { if (dma_transfer_remaining == 0) { // transfer finished, disable the channel HAL_DMA_DeInit(&DMA_Handle); - HAL_NVIC_DisableIRQ(GPDMA1_Channel0_IRQn); + NVIC_DisableIRQ(GPDMA1_Channel0_IRQn); + DMA_Handle.Instance = NULL; data_src = NULL; data_dst = NULL; @@ -52,6 +58,8 @@ void GPDMA1_Channel0_IRQHandler(void) { bg_copy_callback(); } } + + mpu_restore(mpu_mode); } bool bg_copy_pending(void) { return dma_transfer_remaining > 0; } @@ -97,8 +105,8 @@ void bg_copy_start_const_out_8(const uint8_t *src, uint8_t *dst, size_t size, DMA_CHANNEL_SRC_SEC | DMA_CHANNEL_DEST_SEC); - HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, IRQ_PRI_DMA, 0); - HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn); + NVIC_SetPriority(GPDMA1_Channel0_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(GPDMA1_Channel0_IRQn); HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)src, (uint32_t)dst, data_to_send); } @@ -106,9 +114,14 @@ void bg_copy_start_const_out_8(const uint8_t *src, uint8_t *dst, size_t size, void bg_copy_abort(void) { dma_transfer_remaining = 0; dma_data_transferred = 0; - HAL_DMA_Abort(&DMA_Handle); - HAL_DMA_DeInit(&DMA_Handle); - HAL_NVIC_DisableIRQ(GPDMA1_Channel0_IRQn); + if (DMA_Handle.Instance != NULL) { + HAL_DMA_Abort(&DMA_Handle); + HAL_DMA_DeInit(&DMA_Handle); + DMA_Handle.Instance = NULL; + } + NVIC_DisableIRQ(GPDMA1_Channel0_IRQn); data_src = NULL; data_dst = NULL; } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/boot_args.c b/core/embed/trezorhal/stm32u5/boot_args.c deleted file mode 120000 index ea7e8b6c203..00000000000 --- a/core/embed/trezorhal/stm32u5/boot_args.c +++ /dev/null @@ -1 +0,0 @@ -../stm32f4/boot_args.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/bootutils.c b/core/embed/trezorhal/stm32u5/bootutils.c new file mode 120000 index 00000000000..cdb656edf34 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/bootutils.c @@ -0,0 +1 @@ +../stm32f4/bootutils.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/common.c b/core/embed/trezorhal/stm32u5/common.c index 0541aabbc0c..5efbb408874 100644 --- a/core/embed/trezorhal/stm32u5/common.c +++ b/core/embed/trezorhal/stm32u5/common.c @@ -23,100 +23,11 @@ #include "common.h" #include "display.h" +#include "error_handling.h" #include "flash_otp.h" #include "model.h" #include "platform.h" #include "rand.h" #include "secret.h" -#include "supervise.h" #include "stm32u5xx_ll_utils.h" - -uint32_t systick_val_copy = 0; - -// from util.s -extern void shutdown_privileged(void); - -void __attribute__((noreturn)) trezor_shutdown(void) { - display_finish_actions(); - - __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 hal_delay(uint32_t ms) { HAL_Delay(ms); } -uint32_t hal_ticks_ms() { return HAL_GetTick(); } -void hal_delay_us(uint16_t delay_us) { - uint32_t val = svc_get_systick_val(); - uint32_t t = hal_ticks_ms() * 1000 + - (((SystemCoreClock / 1000) - val) / (SystemCoreClock / 1000000)); - uint32_t t2 = t; - do { - val = svc_get_systick_val(); - t2 = hal_ticks_ms() * 1000 + - (((SystemCoreClock / 1000) - val) / (SystemCoreClock / 1000000)); - } while ((t2 - t) < delay_us); -} - -uint32_t __stack_chk_guard = 0; - -void __attribute__((noreturn)) __stack_chk_fail(void) { - error_shutdown("(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 invalidate_firmware(void) { - // on stm32u5, we need to disable the instruction cache before erasing the - // firmware - otherwise, the write check will fail - ICACHE->CR &= ~ICACHE_CR_EN; - - // erase start of the firmware (metadata) -> invalidate FW - ensure(flash_unlock_write(), NULL); - for (int i = 0; i < (1024 / FLASH_BLOCK_SIZE); i += FLASH_BLOCK_SIZE) { - flash_block_t data = {0}; - ensure(flash_area_write_block(&FIRMWARE_AREA, i * FLASH_BLOCK_SIZE, data), - NULL); - } - ensure(flash_lock_write(), NULL); -} diff --git a/core/embed/trezorhal/stm32u5/consumption_mask.c b/core/embed/trezorhal/stm32u5/consumption_mask.c index fcc51b3f326..3d81dc184e1 100644 --- a/core/embed/trezorhal/stm32u5/consumption_mask.c +++ b/core/embed/trezorhal/stm32u5/consumption_mask.c @@ -20,6 +20,8 @@ #include STM32_HAL_H #include "rng.h" +#ifdef KERNEL_MODE + #define SAMPLES 119 #define TIMER_PERIOD 16000 // cca 10 KHz @ 160MHz @@ -138,3 +140,5 @@ void consumption_mask_init(void) { HAL_DMAEx_List_Start(&dma_handle); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/displays/dsi.c b/core/embed/trezorhal/stm32u5/displays/dsi.c index 8e44fabb416..775a451a717 100644 --- a/core/embed/trezorhal/stm32u5/displays/dsi.c +++ b/core/embed/trezorhal/stm32u5/displays/dsi.c @@ -59,6 +59,7 @@ /* Includes ------------------------------------------------------------------*/ #include "colors.h" +#include "irq.h" #include "stdint.h" #include "string.h" #include STM32_HAL_H @@ -82,15 +83,6 @@ #define BSP_BUTTON_USER_IT_PRIORITY \ 0x0FUL /* Default is lowest priority level */ -/* LCD interrupt priorities */ -#define BSP_LCD_GFXMMU_IT_PRIORITY \ - 0x0FUL /* Default is lowest priority level \ - */ -#define BSP_LCD_LTDC_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ -#define BSP_LCD_DSI_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ - -/* HSPI RAM interrupt priority */ -#define BSP_HSPI_RAM_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ #define LCD_PIXEL_FORMAT_ARGB8888 \ 0x00000000U /*!< ARGB8888 LTDC pixel format \ */ @@ -1356,8 +1348,8 @@ static void GFXMMU_MspInit(GFXMMU_HandleTypeDef *hgfxmmu) { __HAL_RCC_GFXMMU_CLK_ENABLE(); /* Enable GFXMMU interrupt */ - HAL_NVIC_SetPriority(GFXMMU_IRQn, BSP_LCD_GFXMMU_IT_PRIORITY, 0); - HAL_NVIC_EnableIRQ(GFXMMU_IRQn); + NVIC_SetPriority(GFXMMU_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(GFXMMU_IRQn); } /** @@ -1370,7 +1362,7 @@ static void GFXMMU_MspDeInit(GFXMMU_HandleTypeDef *hgfxmmu) { UNUSED(hgfxmmu); /* Disable GFXMMU interrupt */ - HAL_NVIC_DisableIRQ(GFXMMU_IRQn); + NVIC_DisableIRQ(GFXMMU_IRQn); /* GFXMMU clock disable */ __HAL_RCC_GFXMMU_CLK_DISABLE(); @@ -1389,11 +1381,11 @@ static void LTDC_MspInit(LTDC_HandleTypeDef *hltdc) { __HAL_RCC_LTDC_CLK_ENABLE(); /* Enable LTDC interrupt */ - HAL_NVIC_SetPriority(LTDC_IRQn, BSP_LCD_LTDC_IT_PRIORITY, 0); - HAL_NVIC_EnableIRQ(LTDC_IRQn); + NVIC_SetPriority(LTDC_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(LTDC_IRQn); - HAL_NVIC_SetPriority(LTDC_ER_IRQn, BSP_LCD_LTDC_IT_PRIORITY, 0); - HAL_NVIC_EnableIRQ(LTDC_ER_IRQn); + NVIC_SetPriority(LTDC_ER_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(LTDC_ER_IRQn); } /** @@ -1406,8 +1398,8 @@ static void LTDC_MspDeInit(LTDC_HandleTypeDef *hltdc) { UNUSED(hltdc); /* Disable LTDC interrupts */ - HAL_NVIC_DisableIRQ(LTDC_ER_IRQn); - HAL_NVIC_DisableIRQ(LTDC_IRQn); + NVIC_DisableIRQ(LTDC_ER_IRQn); + NVIC_DisableIRQ(LTDC_IRQn); /* LTDC clock disable */ __HAL_RCC_LTDC_CLK_DISABLE(); @@ -1514,8 +1506,8 @@ static void DSI_MspInit(DSI_HandleTypeDef *hdsi) { /* Enable DSI NVIC interrupt */ /* Default is lowest priority level */ - HAL_NVIC_SetPriority(DSI_IRQn, 0x0FUL, 0); - HAL_NVIC_EnableIRQ(DSI_IRQn); + NVIC_SetPriority(DSI_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(DSI_IRQn); } /** @@ -1550,7 +1542,7 @@ static void DSI_MspDeInit(DSI_HandleTypeDef *hdsi) { __HAL_RCC_DSI_RELEASE_RESET(); /* Disable DSI interrupts */ - HAL_NVIC_DisableIRQ(DSI_IRQn); + NVIC_DisableIRQ(DSI_IRQn); } void display_pixeldata(uint16_t c) { @@ -1662,7 +1654,7 @@ int display_orientation(int degrees) { return degrees; } int display_get_orientation(void) { return 0; } int display_backlight(int val) { return val; } -void display_init(void) { +void display_init_all(void) { RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Initializes the common periph clock diff --git a/core/embed/trezorhal/stm32u5/entropy.c b/core/embed/trezorhal/stm32u5/entropy.c new file mode 100644 index 00000000000..695371d3048 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/entropy.c @@ -0,0 +1,64 @@ +/* + * 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 "entropy.h" +#include "flash_otp.h" +#include "model.h" +#include "mpu.h" +#include "rand.h" + +#include "stm32u5xx_ll_utils.h" + +#ifdef KERNEL_MODE + +static uint8_t g_hw_entropy[HW_ENTROPY_LEN]; + +void entropy_init(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + + // collect entropy from UUID + uint32_t w = LL_GetUID_Word0(); + memcpy(g_hw_entropy, &w, 4); + w = LL_GetUID_Word1(); + memcpy(g_hw_entropy + 4, &w, 4); + w = LL_GetUID_Word2(); + memcpy(g_hw_entropy + 8, &w, 4); + + mpu_restore(mpu_mode); + + // 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, g_hw_entropy + 12, + FLASH_OTP_BLOCK_SIZE), + NULL); +} + +void entropy_get(uint8_t *buf) { memcpy(buf, g_hw_entropy, HW_ENTROPY_LEN); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/fault_handlers.c b/core/embed/trezorhal/stm32u5/fault_handlers.c deleted file mode 100644 index bf19c8e8ef3..00000000000 --- a/core/embed/trezorhal/stm32u5/fault_handlers.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "common.h" - -void fault_handlers_init(void) { - // Enable BUS fault and USAGE fault handlers - SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk); -} - -void HardFault_Handler(void) { error_shutdown("(HF)"); } - -void MemManage_Handler(void) { error_shutdown("(MM)"); } - -void BusFault_Handler(void) { error_shutdown("(BF)"); } - -void UsageFault_Handler(void) { - if (SCB->CFSR & SCB_CFSR_STKOF_Msk) { - // Stack overflow - extern uint8_t _estack; // linker script symbol - // Fix stack pointer - __set_MSP((uint32_t)&_estack); - error_shutdown("(SO)"); - } else { - // Other error - error_shutdown("(UF)"); - } -} - -void SecureFault_Handler(void) { error_shutdown("(SF)"); } - -void GTZC_IRQHandler(void) { error_shutdown("(IA)"); } - -void NMI_Handler(void) { - // Clock Security System triggered NMI - if ((RCC->CIFR & RCC_CIFR_CSSF) != 0) { - error_shutdown("(CS)"); - } -} diff --git a/core/embed/trezorhal/stm32u5/flash.c b/core/embed/trezorhal/stm32u5/flash.c index 3f72031cf7d..f25c2ba6c85 100644 --- a/core/embed/trezorhal/stm32u5/flash.c +++ b/core/embed/trezorhal/stm32u5/flash.c @@ -26,6 +26,8 @@ #include "flash.h" #include "model.h" +#ifdef KERNEL_MODE + #ifdef STM32U585xx #define FLASH_BANK_PAGES 128 #define FLASH_SECTOR_COUNT (FLASH_BANK_PAGES * 2) @@ -213,3 +215,5 @@ secbool flash_write_block(uint16_t sector, uint32_t offset, const flash_block_t block) { return flash_write_quadword(sector, offset, block); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/flash_otp.c b/core/embed/trezorhal/stm32u5/flash_otp.c index c5c6d7aa618..9486ccf7a44 100644 --- a/core/embed/trezorhal/stm32u5/flash_otp.c +++ b/core/embed/trezorhal/stm32u5/flash_otp.c @@ -22,6 +22,9 @@ #include "flash_otp.h" #include "common.h" #include "flash.h" +#include "mpu.h" + +#ifdef KERNEL_MODE void flash_otp_init() { // intentionally left empty @@ -33,10 +36,16 @@ secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, offset + datalen > FLASH_OTP_BLOCK_SIZE) { return secfalse; } + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + for (uint8_t i = 0; i < datalen; i++) { data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i); } + + mpu_restore(mpu_mode); + return sectrue; } @@ -49,6 +58,9 @@ secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, offset + datalen > FLASH_OTP_BLOCK_SIZE) { return secfalse; } + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + ensure(flash_unlock_write(), NULL); for (uint8_t i = 0; i < datalen; i += 16) { uint32_t address = @@ -58,35 +70,62 @@ secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, NULL); } ensure(flash_lock_write(), NULL); + + mpu_restore(mpu_mode); + return sectrue; } secbool flash_otp_lock(uint8_t block) { + if (block >= FLASH_OTP_NUM_BLOCKS) { + return secfalse; + } + // 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); + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + 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) { + mpu_restore(mpu_mode); return secfalse; } } + + mpu_restore(mpu_mode); + return sectrue; } secbool flash_otp_is_locked(uint8_t block) { + if (block >= FLASH_OTP_NUM_BLOCKS) { + return secfalse; + } + + secbool is_locked = secfalse; + // 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); + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) { if (addr[i] != 0xFF) { - return sectrue; + is_locked = sectrue; + break; } } - return secfalse; + + mpu_restore(mpu_mode); + + return is_locked; } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/fwutils.c b/core/embed/trezorhal/stm32u5/fwutils.c new file mode 120000 index 00000000000..8968a5a0247 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/fwutils.c @@ -0,0 +1 @@ +../stm32f4/fwutils.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.c b/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.c index 4f81f5ba6c7..7b1168c50b1 100644 --- a/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.c +++ b/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.c @@ -25,10 +25,12 @@ #include "common.h" #include "drv2625.h" #include "haptic.h" -#include "i2c.h" +#include "i2c_bus.h" #include STM32_HAL_H +#ifdef KERNEL_MODE + // Maximum amplitude of the vibration effect // (DRV2625 supports 7-bit amplitude) #define MAX_AMPLITUDE 127 @@ -64,6 +66,8 @@ typedef struct { // Set if driver is initialized bool initialized; + // I2c bus where the touch controller is connected + i2c_bus_t *i2c_bus; // Set if driver is enabled bool enabled; // Set to if real-time playing is activated. @@ -78,10 +82,26 @@ static haptic_driver_t g_haptic_driver = { .initialized = false, }; -static bool drv2625_set_reg(uint8_t addr, uint8_t value) { - uint8_t data[] = {addr, value}; - return i2c_transmit(DRV2625_I2C_INSTANCE, DRV2625_I2C_ADDRESS, data, - sizeof(data), 1) == HAL_OK; +static bool drv2625_set_reg(i2c_bus_t *bus, uint8_t addr, uint8_t value) { + i2c_op_t ops[] = { + { + .flags = I2C_FLAG_TX | I2C_FLAG_EMBED, + .size = 2, + .data = {addr, value}, + }, + }; + + i2c_packet_t pkt = { + .address = DRV2625_I2C_ADDRESS, + .op_count = ARRAY_LENGTH(ops), + .ops = ops, + }; + + if (I2C_STATUS_OK != i2c_bus_submit_and_wait(bus, &pkt)) { + return false; + } + + return true; } bool haptic_init(void) { @@ -93,34 +113,41 @@ bool haptic_init(void) { memset(driver, 0, sizeof(haptic_driver_t)); + driver->i2c_bus = i2c_bus_open(DRV2625_I2C_INSTANCE); + if (driver->i2c_bus == NULL) { + goto cleanup; + } + // select library - if (!drv2625_set_reg(DRV2625_REG_LIBRARY, + if (!drv2625_set_reg(driver->i2c_bus, DRV2625_REG_LIBRARY, LIB_SEL | DRV2625_REG_LIBRARY_GAIN_25)) { - return false; + goto cleanup; } if (!drv2625_set_reg( - DRV2625_REG_LRAERM, + driver->i2c_bus, DRV2625_REG_LRAERM, LRA_ERM_SEL | LOOP_SEL | DRV2625_REG_LRAERM_AUTO_BRK_OL)) { + goto cleanup; } - if (!drv2625_set_reg(DRV2625_REG_OD_CLAMP, ACTUATOR_OD_CLAMP)) { - return false; + if (!drv2625_set_reg(driver->i2c_bus, DRV2625_REG_OD_CLAMP, + ACTUATOR_OD_CLAMP)) { + goto cleanup; } - if (!drv2625_set_reg(DRV2625_REG_LRA_WAVE_SHAPE, + if (!drv2625_set_reg(driver->i2c_bus, DRV2625_REG_LRA_WAVE_SHAPE, DRV2625_REG_LRA_WAVE_SHAPE_SINE)) { - return false; + goto cleanup; } - if (!drv2625_set_reg(DRV2625_REG_OL_LRA_PERIOD_LO, + if (!drv2625_set_reg(driver->i2c_bus, DRV2625_REG_OL_LRA_PERIOD_LO, ACTUATOR_LRA_PERIOD & 0xFF)) { - return false; + goto cleanup; } - if (!drv2625_set_reg(DRV2625_REG_OL_LRA_PERIOD_HI, + if (!drv2625_set_reg(driver->i2c_bus, DRV2625_REG_OL_LRA_PERIOD_HI, ACTUATOR_LRA_PERIOD >> 8)) { - return false; + goto cleanup; } GPIO_InitTypeDef GPIO_InitStructure = {0}; @@ -158,6 +185,11 @@ bool haptic_init(void) { driver->enabled = true; return true; + +cleanup: + i2c_bus_close(driver->i2c_bus); + memset(driver, 0, sizeof(haptic_driver_t)); + return false; } void haptic_deinit(void) { @@ -167,6 +199,8 @@ void haptic_deinit(void) { return; } + i2c_bus_close(driver->i2c_bus); + // TODO: deinitialize GPIOs and the TIMER memset(driver, 0, sizeof(haptic_driver_t)); @@ -197,7 +231,7 @@ static bool haptic_play_rtp(int8_t amplitude, uint16_t duration_ms) { if (!driver->playing_rtp) { if (!drv2625_set_reg( - DRV2625_REG_MODE, + driver->i2c_bus, DRV2625_REG_MODE, DRV2625_REG_MODE_RTP | DRV2625_REG_MODE_TRGFUNC_ENABLE)) { return false; } @@ -205,7 +239,7 @@ static bool haptic_play_rtp(int8_t amplitude, uint16_t duration_ms) { driver->playing_rtp = true; } - if (!drv2625_set_reg(DRV2625_REG_RTP, (uint8_t)amplitude)) { + if (!drv2625_set_reg(driver->i2c_bus, DRV2625_REG_RTP, (uint8_t)amplitude)) { return false; } @@ -233,19 +267,20 @@ static bool haptic_play_lib(drv2625_lib_effect_t effect) { driver->playing_rtp = false; - if (!drv2625_set_reg(DRV2625_REG_MODE, DRV2625_REG_MODE_WAVEFORM)) { + if (!drv2625_set_reg(driver->i2c_bus, DRV2625_REG_MODE, + DRV2625_REG_MODE_WAVEFORM)) { return false; } - if (!drv2625_set_reg(DRV2625_REG_WAVESEQ1, effect)) { + if (!drv2625_set_reg(driver->i2c_bus, DRV2625_REG_WAVESEQ1, effect)) { return false; } - if (!drv2625_set_reg(DRV2625_REG_WAVESEQ2, 0)) { + if (!drv2625_set_reg(driver->i2c_bus, DRV2625_REG_WAVESEQ2, 0)) { return false; } - if (!drv2625_set_reg(DRV2625_REG_GO, DRV2625_REG_GO_GO)) { + if (!drv2625_set_reg(driver->i2c_bus, DRV2625_REG_GO, DRV2625_REG_GO_GO)) { return false; } @@ -291,3 +326,5 @@ bool haptic_play_custom(int8_t amplitude_pct, uint16_t duration_ms) { bool haptic_test(uint16_t duration_ms) { return haptic_play_rtp(PRODTEST_EFFECT_AMPLITUDE, duration_ms); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.h b/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.h index 40a0d5e594f..fe67b2c77ff 100644 --- a/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.h +++ b/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.h @@ -2,8 +2,7 @@ #define TREZOR_HAL_DRV_2625_H // I2C address of the DRV2625 on the I2C bus. -// `<< 1` is required because the HAL expects the address to be shifted by 1. -#define DRV2625_I2C_ADDRESS (0x5A << 1) +#define DRV2625_I2C_ADDRESS 0x5A // ------------------------------------------------------------ // DRV2625 registers diff --git a/core/embed/trezorhal/stm32u5/hash_processor.c b/core/embed/trezorhal/stm32u5/hash_processor.c index 57993663af9..6d048abfb52 100644 --- a/core/embed/trezorhal/stm32u5/hash_processor.c +++ b/core/embed/trezorhal/stm32u5/hash_processor.c @@ -4,8 +4,11 @@ #include STM32_HAL_H #include "irq.h" #include "memzero.h" +#include "mpu.h" #include "sha2.h" +#ifdef KERNEL_MODE + HASH_HandleTypeDef hhash = {0}; DMA_HandleTypeDef DMA_Handle = {0}; @@ -40,11 +43,15 @@ void hash_processor_init(void) { DMA_Handle.Parent = &hhash; - HAL_NVIC_SetPriority(GPDMA1_Channel12_IRQn, IRQ_PRI_DMA, 0); - HAL_NVIC_EnableIRQ(GPDMA1_Channel12_IRQn); + NVIC_SetPriority(GPDMA1_Channel12_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(GPDMA1_Channel12_IRQn); } -void GPDMA1_Channel12_IRQHandler(void) { HAL_DMA_IRQHandler(&DMA_Handle); } +void GPDMA1_Channel12_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + HAL_DMA_IRQHandler(&DMA_Handle); + mpu_restore(mpu_mode); +} static void hash_processor_sha256_calc_dma(const uint8_t *data, uint32_t len, uint8_t *hash) { @@ -125,3 +132,5 @@ void hash_processor_sha256_final(hash_sha265_context_t *ctx, uint8_t *output) { memcpy(output, tmp_out, SHA256_DIGEST_LENGTH); memzero(tmp_out, sizeof(tmp_out)); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/i2c.c b/core/embed/trezorhal/stm32u5/i2c.c deleted file mode 100644 index 70b568b0107..00000000000 --- a/core/embed/trezorhal/stm32u5/i2c.c +++ /dev/null @@ -1,179 +0,0 @@ - - -#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_0, - .SclPort = I2C_INSTANCE_0_SCL_PORT, - .SdaPort = I2C_INSTANCE_0_SDA_PORT, - .SclPin = I2C_INSTANCE_0_SCL_PIN, - .SdaPin = I2C_INSTANCE_0_SDA_PIN, - .PinAF = I2C_INSTANCE_0_PIN_AF, - .ResetReg = I2C_INSTANCE_0_RESET_REG, - .ResetBit = I2C_INSTANCE_0_RESET_BIT, - }, -#ifdef I2C_INSTANCE_1 - { - .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, - }, -#endif -#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 - -}; - -/* - * Using calculation from STM32CubeMX - * PCLKx as source, assumed 160MHz - * Fast mode, freq = 400kHz, Rise time = 250ns, Fall time = 100ns - * Fast mode, freq = 200kHz, Rise time = 250ns, Fall time = 100ns - * SCLH and SCLL are manually modified to achieve more symmetric clock - */ -#define I2C_TIMING_400000_Hz 0x30D22728 -#define I2C_TIMING_200000_Hz 0x30D2595A -#define I2C_TIMING I2C_TIMING_200000_Hz - -void i2c_init_instance(uint16_t idx, i2c_instance_t *instance) { - if (i2c_handle[idx].Instance) { - return; - } - - GPIO_InitTypeDef GPIO_InitStructure = {0}; - - // 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_TIMING; - 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])) { - error_shutdown("I2C was not loaded properly."); - return; - } -} - -void i2c_init(void) { - // enable I2C clock - I2C_INSTANCE_0_CLK_EN(); - I2C_INSTANCE_0_SCL_CLK_EN(); - I2C_INSTANCE_0_SDA_CLK_EN(); - i2c_init_instance(0, &i2c_defs[0]); - -#ifdef I2C_INSTANCE_1 - I2C_INSTANCE_1_CLK_EN(); - I2C_INSTANCE_1_SCL_CLK_EN(); - I2C_INSTANCE_1_SDA_CLK_EN(); - i2c_init_instance(1, &i2c_defs[1]); -#endif - -#ifdef I2C_INSTANCE_2 - I2C_INSTANCE_2_CLK_EN(); - I2C_INSTANCE_2_SCL_CLK_EN(); - I2C_INSTANCE_2_SDA_CLK_EN(); - i2c_init_instance(2, &i2c_defs[2]); -#endif -} - -void i2c_deinit(uint16_t idx) { - 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 deleted file mode 120000 index d9235cabc4b..00000000000 --- a/core/embed/trezorhal/stm32u5/i2c.h +++ /dev/null @@ -1 +0,0 @@ -../stm32f4/i2c.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/i2c_bus.c b/core/embed/trezorhal/stm32u5/i2c_bus.c new file mode 100644 index 00000000000..2a0a1211aa3 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/i2c_bus.c @@ -0,0 +1,911 @@ +/* + * 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 TREZOR_BOARD + +#include + +#include "common.h" +#include "i2c_bus.h" +#include "irq.h" +#include "mpu.h" +#include "systimer.h" + +#ifdef KERNEL_MODE + +// Using calculation from STM32CubeMX +// PCLKx as source, assumed 160MHz +// Fast mode, freq = 400kHz, Rise time = 250ns, Fall time = 100ns +// Fast mode, freq = 200kHz, Rise time = 250ns, Fall time = 100ns +// SCLH and SCLL are manually modified to achieve more symmetric clock +#define I2C_TIMING_400000_Hz 0x30D22728 +#define I2C_TIMING_200000_Hz 0x30D2595A +#define I2C_TIMING I2C_TIMING_200000_Hz + +// We expect the I2C bus to be running at ~200kHz +// and max response time of the device is 1000us +#define I2C_BUS_CHAR_TIMEOUT (50 + 5) // us +#define I2C_BUS_OP_TIMEOUT 1000 // us + +#define I2C_BUS_TIMEOUT(n) \ + ((I2C_BUS_CHAR_TIMEOUT * (1 + n) + I2C_BUS_OP_TIMEOUT + 999) / 1000) + +// I2C bus hardware definition +typedef struct { + // I2C controller registers + I2C_TypeDef* regs; + // SCL pin GPIO port + GPIO_TypeDef* scl_port; + // SDA pin GPIO port + GPIO_TypeDef* sda_port; + // SCL pin number + uint16_t scl_pin; + // SDA pin number + uint16_t sda_pin; + // Alternate function for SCL and SDA pins + uint8_t pin_af; + // Register for I2C controller reset + volatile uint32_t* reset_reg; + // Reset bit specific for this I2C controller + uint32_t reset_bit; + // I2C event IRQ number + uint32_t ev_irq; + // I2C error IRQ number + uint32_t er_irq; + // Guard time [us] between STOP and START condition. + // If zero, the guard time is not used. + uint16_t guard_time; +} i2c_bus_def_t; + +// I2C bus hardware definitions +static const i2c_bus_def_t g_i2c_bus_def[I2C_COUNT] = { + { + .regs = I2C_INSTANCE_0, + .scl_port = I2C_INSTANCE_0_SCL_PORT, + .sda_port = I2C_INSTANCE_0_SDA_PORT, + .scl_pin = I2C_INSTANCE_0_SCL_PIN, + .sda_pin = I2C_INSTANCE_0_SDA_PIN, + .pin_af = I2C_INSTANCE_0_PIN_AF, + .reset_reg = I2C_INSTANCE_0_RESET_REG, + .reset_bit = I2C_INSTANCE_0_RESET_BIT, + .ev_irq = I2C_INSTANCE_0_EV_IRQn, + .er_irq = I2C_INSTANCE_0_ER_IRQn, + .guard_time = I2C_INSTANCE_0_GUARD_TIME, + }, +#ifdef I2C_INSTANCE_1 + { + .regs = I2C_INSTANCE_1, + .scl_port = I2C_INSTANCE_1_SCL_PORT, + .sda_port = I2C_INSTANCE_1_SDA_PORT, + .scl_pin = I2C_INSTANCE_1_SCL_PIN, + .sda_pin = I2C_INSTANCE_1_SDA_PIN, + .pin_af = I2C_INSTANCE_1_PIN_AF, + .reset_reg = I2C_INSTANCE_1_RESET_REG, + .reset_bit = I2C_INSTANCE_1_RESET_BIT, + .ev_irq = I2C_INSTANCE_1_EV_IRQn, + .er_irq = I2C_INSTANCE_1_ER_IRQn, + .guard_time = I2C_INSTANCE_1_GUARD_TIME, + }, +#endif +#ifdef I2C_INSTANCE_2 + { + .regs = I2C_INSTANCE_2, + .scl_port = I2C_INSTANCE_2_SCL_PORT, + .sda_port = I2C_INSTANCE_2_SDA_PORT, + .scl_pin = I2C_INSTANCE_2_SCL_PIN, + .sda_pin = I2C_INSTANCE_2_SDA_PIN, + .pin_af = I2C_INSTANCE_2_PIN_AF, + .reset_reg = I2C_INSTANCE_2_RESET_REG, + .reset_bit = I2C_INSTANCE_2_RESET_BIT, + .ev_irq = I2C_INSTANCE_2_EV_IRQn, + .er_irq = I2C_INSTANCE_2_ER_IRQn, + .guard_time = I2C_INSTANCE_2_GUARD_TIME, + }, +#endif +}; + +struct i2c_bus { + // Number of references to the bus + // (0 means the bus is not initialized) + uint32_t refcount; + + // Hardware definition + const i2c_bus_def_t* def; + + // Timer for timeout handling + systimer_t* timer; + + // Head of the packet queue + // (this packet is currently being processed) + i2c_packet_t* queue_head; + // Tail of the packet queue + // (this packet is the last in the queue) + i2c_packet_t* queue_tail; + + // Next operation index in the current packet + // == 0 => no operation is being processed + // == queue_head->op_count => no more operations + int next_op; + + // Points to the data buffer of the current operation + uint8_t* buff_ptr; + // Remaining number of bytes of the buffer to transfer + uint16_t buff_size; + // Remaining number of bytes of the current operation + // (if the transfer is split into multiple operations it + // may be different from buff_size) + uint16_t transfer_size; + // For case of split transfer, points to the next operation + // that is part of the current transfer + int transfer_op; + + // Set if the STOP condition is requested after the current operation + // when data transfer is completed. + bool stop_requested; + // Set if pending transaction is being aborted + bool abort_pending; + // Set if NACK was detected + bool nack; + // Data for clearing TXIS interrupt flag + // during an invalid or abort state + uint8_t dummy_data; + + // Flag indicating that the completion callback is being executed + bool callback_executed; + + // The last time [us] the STOP condition was issued + uint64_t stop_time; +}; + +// I2C bus driver instances +static i2c_bus_t g_i2c_bus_driver[I2C_COUNT] = {0}; + +// Check if the I2C bus pointer is valid +static inline bool i2c_bus_ptr_valid(const i2c_bus_t* bus) { + if (bus >= &g_i2c_bus_driver[0] && bus < &g_i2c_bus_driver[I2C_COUNT]) { + uintptr_t offset = (uintptr_t)bus - (uintptr_t)&g_i2c_bus_driver[0]; + if (offset % sizeof(i2c_bus_t) == 0) { + return bus->refcount > 0; + } + } + return false; +} + +// forward declarations +static void i2c_bus_timer_callback(void* context); +static void i2c_bus_head_continue(i2c_bus_t* bus); + +static void i2c_bus_unlock(i2c_bus_t* bus) { + const i2c_bus_def_t* def = bus->def; + + GPIO_InitTypeDef GPIO_InitStructure = {0}; + + // Set SDA and SCL high + HAL_GPIO_WritePin(def->sda_port, def->sda_pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(def->scl_port, def->scl_pin, GPIO_PIN_SET); + + // Configure SDA and SCL as open-drain output + // and connect to the I2C peripheral + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + + GPIO_InitStructure.Pin = def->scl_pin; + HAL_GPIO_Init(def->scl_port, &GPIO_InitStructure); + + GPIO_InitStructure.Pin = def->sda_pin; + HAL_GPIO_Init(def->sda_port, &GPIO_InitStructure); + + uint32_t clock_count = 16; + + while ((HAL_GPIO_ReadPin(def->sda_port, def->sda_pin) == GPIO_PIN_RESET) && + (clock_count-- > 0)) { + // Clock SCL + HAL_GPIO_WritePin(def->scl_port, def->scl_pin, GPIO_PIN_RESET); + systick_delay_us(10); + HAL_GPIO_WritePin(def->scl_port, def->scl_pin, GPIO_PIN_SET); + systick_delay_us(10); + } +} + +static void i2c_bus_deinit(i2c_bus_t* bus) { + const i2c_bus_def_t* def = bus->def; + + systimer_delete(bus->timer); + + if (bus->def == NULL) { + return; + } + + NVIC_DisableIRQ(def->ev_irq); + NVIC_DisableIRQ(def->er_irq); + + I2C_TypeDef* regs = def->regs; + + // Disable I2C peripheral + regs->CR1 = 0; + + // Reset I2C peripheral + *def->reset_reg |= def->reset_bit; + *def->reset_reg &= ~def->reset_bit; + + bus->def = NULL; +} + +static bool i2c_bus_init(i2c_bus_t* bus, int bus_index) { + memset(bus, 0, sizeof(i2c_bus_t)); + + switch (bus_index) { + case 0: + // enable I2C clock + I2C_INSTANCE_0_CLK_EN(); + I2C_INSTANCE_0_SCL_CLK_EN(); + I2C_INSTANCE_0_SDA_CLK_EN(); + break; + +#ifdef I2C_INSTANCE_1 + case 1: + I2C_INSTANCE_1_CLK_EN(); + I2C_INSTANCE_1_SCL_CLK_EN(); + I2C_INSTANCE_1_SDA_CLK_EN(); + break; +#endif + +#ifdef I2C_INSTANCE_2 + case 2: + I2C_INSTANCE_2_CLK_EN(); + I2C_INSTANCE_2_SCL_CLK_EN(); + I2C_INSTANCE_2_SDA_CLK_EN(); + break; +#endif + default: + goto cleanup; + } + + const i2c_bus_def_t* def = &g_i2c_bus_def[bus_index]; + + bus->def = def; + + // Unlocks potentially locked I2C bus by + // generating several clock pulses on SCL while SDA is low + i2c_bus_unlock(bus); + + GPIO_InitTypeDef GPIO_InitStructure = {0}; + + // Configure SDA and SCL as open-drain output + // and connect to the I2C peripheral + GPIO_InitStructure.Mode = GPIO_MODE_AF_OD; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + + GPIO_InitStructure.Alternate = def->pin_af; + GPIO_InitStructure.Pin = def->scl_pin; + HAL_GPIO_Init(def->scl_port, &GPIO_InitStructure); + + GPIO_InitStructure.Alternate = def->pin_af; + GPIO_InitStructure.Pin = def->sda_pin; + HAL_GPIO_Init(def->sda_port, &GPIO_InitStructure); + + // Reset I2C peripheral + *def->reset_reg |= def->reset_bit; + *def->reset_reg &= ~def->reset_bit; + + I2C_TypeDef* regs = def->regs; + + // Configure I2C peripheral + regs->CR1 = 0; + regs->TIMINGR = I2C_TIMING; + regs->CR2 = 0; + regs->OAR1 = 0; + regs->OAR2 = 0; + regs->CR1 |= I2C_CR1_PE; + + // Configure I2C interrupts + regs->CR1 |= I2C_CR1_ERRIE | I2C_CR1_NACKIE | I2C_CR1_STOPIE | I2C_CR1_TCIE | + I2C_CR1_RXIE | I2C_CR1_TXIE; + + NVIC_SetPriority(def->ev_irq, IRQ_PRI_NORMAL); + NVIC_SetPriority(def->er_irq, IRQ_PRI_NORMAL); + + NVIC_EnableIRQ(def->ev_irq); + NVIC_EnableIRQ(def->er_irq); + + bus->timer = systimer_create(i2c_bus_timer_callback, bus); + if (bus->timer == NULL) { + goto cleanup; + } + + return true; + +cleanup: + i2c_bus_deinit(bus); + return false; +} + +i2c_bus_t* i2c_bus_open(uint8_t bus_index) { + if (bus_index >= I2C_COUNT) { + return NULL; + } + + i2c_bus_t* bus = &g_i2c_bus_driver[bus_index]; + + if (bus->refcount == 0) { + if (!i2c_bus_init(bus, bus_index)) { + return NULL; + } + } + + ++bus->refcount; + + return bus; +} + +void i2c_bus_close(i2c_bus_t* bus) { + if (!i2c_bus_ptr_valid(bus)) { + return; + } + + if (bus->refcount > 0) { + if (--bus->refcount == 0) { + i2c_bus_deinit(bus); + } + } +} + +i2c_status_t i2c_packet_status(const i2c_packet_t* packet) { + irq_key_t irq_key = irq_lock(); + i2c_status_t status = packet->status; + irq_unlock(irq_key); + return status; +} + +i2c_status_t i2c_packet_wait(const i2c_packet_t* packet) { + while (true) { + i2c_status_t status = i2c_packet_status(packet); + + if (status != I2C_STATUS_PENDING) { + return status; + } + + // Enter sleep mode and wait for any interrupt + __WFI(); + } +} + +static uint8_t i2c_bus_read_buff(i2c_bus_t* bus) { + if (bus->transfer_size > 0) { + while (bus->buff_size == 0 && bus->transfer_op < bus->next_op) { + i2c_op_t* op = &bus->queue_head->ops[bus->transfer_op++]; + if (op->flags & I2C_FLAG_EMBED) { + bus->buff_ptr = op->data; + bus->buff_size = MIN(op->size, sizeof(op->data)); + } else { + bus->buff_ptr = op->ptr; + bus->buff_size = op->size; + } + } + + --bus->transfer_size; + + if (bus->buff_size > 0) { + --bus->buff_size; + return *bus->buff_ptr++; + } + } + + return 0; +} + +static void i2c_bus_write_buff(i2c_bus_t* bus, uint8_t data) { + if (bus->transfer_size > 0) { + while (bus->buff_size == 0 && bus->transfer_op < bus->next_op) { + i2c_op_t* op = &bus->queue_head->ops[bus->transfer_op++]; + if (op->flags & I2C_FLAG_EMBED) { + bus->buff_ptr = op->data; + bus->buff_size = MIN(op->size, sizeof(op->data)); + } else { + bus->buff_ptr = op->ptr; + bus->buff_size = op->size; + } + } + + --bus->transfer_size; + + if (bus->buff_size > 0) { + *bus->buff_ptr++ = data; + --bus->buff_size; + } + } +} + +// Invokes the packet completion callback +static inline void i2c_bus_invoke_callback(i2c_bus_t* bus, i2c_packet_t* packet, + i2c_status_t status) { + packet->status = status; + if (packet->callback) { + bus->callback_executed = true; + packet->callback(packet->context, packet); + bus->callback_executed = false; + } +} + +// Appends the packet to the end of the queue +// Returns true if the queue was empty before +// Expects disabled IRQ or calling from IRQ context +static inline bool i2c_bus_add_packet(i2c_bus_t* bus, i2c_packet_t* packet) { + if (bus->queue_tail == NULL) { + bus->queue_head = packet; + bus->queue_tail = packet; + return true; + } else { + bus->queue_tail->next = packet; + bus->queue_tail = packet; + return false; + } +} + +// Removes the packet from the queue (if present) +// Returns true if the removed we removed head of the queue +// Expects disabled IRQ or calling from IRQ context +static inline bool i2c_bus_remove_packet(i2c_bus_t* bus, i2c_packet_t* packet) { + if (packet == bus->queue_head) { + // Remove head of the queue + bus->queue_head = packet->next; + // If the removed packet was also the tail, reset the tail + if (bus->queue_tail == packet) { + bus->queue_tail = NULL; + } + packet->next = NULL; + return true; + } + + // Remove from the middle or tail of the queue + i2c_packet_t* p = bus->queue_head; + while (p->next != NULL && p->next != packet) { + p = p->next; + } + + if (p->next == packet) { + // The packet found in the queue, remove it + p->next = packet->next; + // Update the tail if necessary + if (bus->queue_tail == packet) { + bus->queue_tail = p; + } + packet->next = NULL; + } + + return false; +} + +i2c_status_t i2c_bus_submit(i2c_bus_t* bus, i2c_packet_t* packet) { + if (!i2c_bus_ptr_valid(bus) || packet == NULL) { + // Invalid bus or packet + return I2C_STATUS_ERROR; + } + + if (packet->next != NULL) { + // Packet is already queued + return I2C_STATUS_ERROR; + } + + packet->status = I2C_STATUS_PENDING; + + // Insert packet into the queue + irq_key_t irq_key = irq_lock(); + if (i2c_bus_add_packet(bus, packet)) { + // The queue was empty, start the operation + if (!bus->callback_executed && !bus->abort_pending) { + i2c_bus_head_continue(bus); + } + } + irq_unlock(irq_key); + + return I2C_STATUS_OK; +} + +void i2c_bus_abort(i2c_bus_t* bus, i2c_packet_t* packet) { + if (!i2c_bus_ptr_valid(bus) || packet == NULL) { + // Invalid bus or packet + return; + } + + irq_key_t irq_key = irq_lock(); + + if (packet->status == I2C_STATUS_PENDING) { + if (i2c_bus_remove_packet(bus, packet) && bus->next_op > 0) { + // The packet was being processed + + if (bus->transfer_size > 0) { + bus->dummy_data = i2c_bus_read_buff(bus); + } + + // Reset internal state + bus->next_op = 0; + bus->buff_ptr = NULL; + bus->buff_size = 0; + bus->transfer_size = 0; + bus->transfer_op = 0; + bus->stop_requested = false; + + // Inform interrupt handler about pending abort + bus->abort_pending = true; + + // Abort operation may fail if the bus is busy or noisy + // so we need to set a timeout. + systimer_set(bus->timer, I2C_BUS_TIMEOUT(2)); + } + + packet->status = I2C_STATUS_ABORTED; + } + + irq_unlock(irq_key); +} + +// Completes the current packet by removing it from the queue +// an invoking the completion callback +// +// Must be called with IRQ disabled or from IRQ context +// Expects the operation is finished +static void i2c_bus_head_complete(i2c_bus_t* bus, i2c_status_t status) { + i2c_packet_t* packet = bus->queue_head; + if (packet != NULL) { + // Remove packet from the queue + i2c_bus_remove_packet(bus, packet); + + // Reset internal state + bus->next_op = 0; + bus->buff_ptr = NULL; + bus->buff_size = 0; + bus->transfer_size = 0; + bus->transfer_op = 0; + bus->stop_requested = false; + bus->abort_pending = false; + + systimer_unset(bus->timer); + + // Invoke the completion callback + i2c_bus_invoke_callback(bus, packet, status); + } +} + +// Starts the next operation in the packet by +// programming the I2C controller +// +// Must be called with IRQ disabled or from IRQ context +// Expects no other operation is being processed +static void i2c_bus_head_continue(i2c_bus_t* bus) { + if (bus->abort_pending) { + systimer_unset(bus->timer); + bus->abort_pending = false; + } + + if (bus->queue_head != NULL) { + i2c_packet_t* packet = bus->queue_head; + + if (bus->next_op < packet->op_count) { + i2c_op_t* op = &packet->ops[bus->next_op++]; + I2C_TypeDef* regs = bus->def->regs; + + uint32_t cr2 = regs->CR2; + cr2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | + I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_SADD_Msk); + + // Set device address + cr2 |= ((packet->address & 0x7F) << 1) << I2C_CR2_SADD_Pos; + + // Get data ptr and its length + if (op->flags & I2C_FLAG_EMBED) { + bus->buff_ptr = op->data; + bus->buff_size = MIN(op->size, sizeof(op->data)); + } else { + bus->buff_ptr = op->ptr; + bus->buff_size = op->size; + } + + // Calculate transfer size + bus->transfer_size = bus->buff_size; + bus->transfer_op = bus->next_op; + + // Include following operations in the transfer if: + // 1) We are not processing the last operation + // 2) STOP condition is not requested in the current operation + // 3) START condition is not requested in the next operation + // 4) The next operation has the same direction + + while ((bus->next_op != packet->op_count) && + ((op->flags & I2C_FLAG_STOP) == 0) && + (((op + 1)->flags & I2C_FLAG_START) == 0) && + (((op + 1)->flags & I2C_FLAG_TX) == (op->flags & I2C_FLAG_TX))) { + // Move to the next operation + op = &packet->ops[bus->next_op++]; + + if (op->flags & I2C_FLAG_EMBED) { + bus->transfer_size += MIN(op->size, sizeof(op->data)); + } else { + bus->transfer_size += op->size; + } + } + + if (bus->transfer_size > 0) { + // I2C controller can handle only 255 bytes at once + // More data will be handled by the TCR interrupt + cr2 |= MIN(255, bus->transfer_size) << I2C_CR2_NBYTES_Pos; + + if (bus->transfer_size > 255) { + cr2 |= I2C_CR2_RELOAD; + } + + if (op->flags & I2C_FLAG_TX) { + // Transmitting has priority over receive. + // Flush TXDR register possibly filled by some previous + // invalid operation or abort. + regs->ISR = I2C_ISR_TXE; + } else if (op->flags & I2C_FLAG_RX) { + // Receive data from the device + cr2 |= I2C_CR2_RD_WRN; + } + } + + // STOP condition: + // 1) if it is explicitly requested + // 2) if it is the last operation in the packet + bus->stop_requested = ((op->flags & I2C_FLAG_STOP) != 0) || + (bus->next_op == packet->op_count); + + bus->nack = false; + + // START condition + cr2 |= I2C_CR2_START; + + // Guard time between operations STOP and START condition + if (bus->def->guard_time > 0) { + while (systick_us() - bus->stop_time < bus->def->guard_time) + ; + } + + regs->CR2 = cr2; + + // Each operation has its own timeout calculated + // based on the number of bytes to transfer and the bus speed + + // expected operation overhead + systimer_set(bus->timer, + I2C_BUS_TIMEOUT(bus->transfer_size) + packet->timeout); + } + } +} + +// Timer callback handling I2C bus timeout +static void i2c_bus_timer_callback(void* context) { + i2c_bus_t* bus = (i2c_bus_t*)context; + + if (bus->abort_pending) { + // Packet abort was not completed in time (STOPF was not detected) + // This may be caused by the bus being busy/noisy. + I2C_TypeDef* regs = bus->def->regs; + + // Reset the I2C controller + regs->CR1 &= ~I2C_CR1_PE; + regs->CR1 |= I2C_CR1_PE; + + // Continue with the next packet + i2c_bus_head_continue(bus); + } else { + // Timeout during normal operation occurred + i2c_packet_t* packet = bus->queue_head; + if (packet != NULL) { + // Determine the status based on the current bus state + I2C_TypeDef* regs = bus->def->regs; + i2c_status_t status; + if ((regs->CR2 & I2C_CR2_START) && (regs->ISR & I2C_ISR_BUSY)) { + // START condition was issued but the bus is still busy + status = I2C_STATUS_BUSY; + } else { + status = I2C_STATUS_TIMEOUT; + } + + // Abort pending packet + i2c_bus_abort(bus, packet); + + // Invoke the completion callback + i2c_bus_invoke_callback(bus, packet, status); + } + } +} + +// I2C bus event interrupt handler +static void i2c_bus_ev_handler(i2c_bus_t* bus) { + I2C_TypeDef* regs = bus->def->regs; + + uint32_t isr = regs->ISR; + + if (isr & I2C_ISR_RXNE) { + // I2C controller receive buffer is not empty. + // The interrupt flag is cleared by reading the RXDR register. + uint8_t received_byte = regs->RXDR; + if (bus->next_op > 0 && bus->transfer_size > 0) { + i2c_bus_write_buff(bus, received_byte); + } else if (bus->abort_pending) { + regs->CR2 |= I2C_CR2_STOP; + } else { + // Invalid state, ignore + } + } + + if (isr & I2C_ISR_TXIS) { + // I2C controller transmit buffer is empty. + // The interrupt flag is cleared by writing the TXDR register. + if (bus->next_op > 0 && bus->transfer_size > 0) { + regs->TXDR = i2c_bus_read_buff(bus); + } else { + regs->TXDR = bus->dummy_data; + if (bus->abort_pending) { + regs->CR2 |= I2C_CR2_STOP; + } else { + // Invalid state, ignore + } + } + } + + if (isr & I2C_ISR_TCR) { + // Data transfer is partially completed and RELOAD is required + if (bus->abort_pending) { + // Packet is being aborted, issue STOP condition + regs->CR2 &= ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD); + regs->CR2 |= I2C_CR2_STOP; + } else if (bus->transfer_size > 0) { + // There are still some bytes left in the current operation buffer + uint32_t cr2 = regs->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD); + + cr2 |= MIN(bus->transfer_size, 255) << I2C_CR2_NBYTES_Pos; + + if (bus->transfer_size > 255) { + // Set RELOAD if we the remaining data is still over + // the 255 bytes limit + cr2 |= I2C_CR2_RELOAD; + } + regs->CR2 = cr2; + } else if (bus->queue_head != NULL) { + // Data transfer is split between two or more operations, + // continues in the next operation + i2c_bus_head_continue(bus); + } else { + // Invalid state, clear the TCR flag + regs->CR2 &= ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD); + regs->CR2 |= I2C_CR2_STOP; + } + } + + if (isr & I2C_ISR_TC) { + // Transfer complete + if (bus->stop_requested || bus->abort_pending) { + // Issue stop condition and wait for ISR_STOPF flag + regs->CR2 |= I2C_CR2_STOP; + } else if (bus->queue_head != NULL) { + // Continue with the next operation + i2c_bus_head_continue(bus); + } else { + // Invalid state, clear the TC flag + regs->CR2 |= I2C_CR2_STOP; + } + } + + if (isr & I2C_ISR_NACKF) { + // Clear the NACKF flag + regs->ICR = I2C_ICR_NACKCF; + bus->nack = true; + // STOP condition is automatically generated + // by the hardware and the STOPF is set later. + } + + if (isr & I2C_ISR_STOPF) { + // Clear the STOPF flag + regs->ICR = I2C_ICR_STOPCF; + + if (bus->def->guard_time > 0) { + bus->stop_time = systick_us(); + } + + if (bus->next_op > 0 && bus->next_op == bus->queue_head->op_count) { + // Last operation in the packet + i2c_bus_head_complete(bus, bus->nack ? I2C_STATUS_NACK : I2C_STATUS_OK); + } + + // Continue with the next operation + // or complete the pending packet and move to the next + i2c_bus_head_continue(bus); + } +} + +// I2C bus error interrupt handler +static void i2c_bus_er_handler(i2c_bus_t* bus) { + I2C_TypeDef* regs = bus->def->regs; + + uint32_t isr = regs->ISR; + + // Clear error flags + regs->ICR = I2C_ICR_BERRCF | I2C_ICR_ARLOCF | I2C_ICR_OVRCF; + + if (isr & I2C_ISR_BERR) { + // Bus error + // Ignore and continue with pending operation + } + + if (isr & I2C_ISR_ARLO) { + if (bus->next_op > 0) { + // Arbitration lost, complete packet with error + i2c_bus_head_complete(bus, I2C_STATUS_ERROR); + // Start the next packet + i2c_bus_head_continue(bus); + } else { + // Packet aborted or invalid state + } + } + + if (isr & I2C_ISR_OVR) { + // This should not happen in master mode + } +} + +// Interrupt handlers + +#ifdef I2C_INSTANCE_0 +void I2C_INSTANCE_0_EV_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_ev_handler(&g_i2c_bus_driver[0]); + mpu_restore(mpu_mode); +} + +void I2C_INSTANCE_0_ER_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_er_handler(&g_i2c_bus_driver[0]); + mpu_restore(mpu_mode); +} +#endif + +#ifdef I2C_INSTANCE_1 +void I2C_INSTANCE_1_EV_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_ev_handler(&g_i2c_bus_driver[1]); + mpu_restore(mpu_mode); +} + +void I2C_INSTANCE_1_ER_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_er_handler(&g_i2c_bus_driver[1]); + mpu_restore(mpu_mode); +} +#endif + +#ifdef I2C_INSTANCE_2 +void I2C_INSTANCE_2_EV_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_ev_handler(&g_i2c_bus_driver[2]); + mpu_restore(mpu_mode); +} + +void I2C_INSTANCE_2_ER_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + i2c_bus_er_handler(&g_i2c_bus_driver[2]); + mpu_restore(mpu_mode); +} +#endif + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/limited_util.s b/core/embed/trezorhal/stm32u5/limited_util.S similarity index 65% rename from core/embed/trezorhal/stm32u5/limited_util.s rename to core/embed/trezorhal/stm32u5/limited_util.S index c9004fd4f2a..0c7cc3c2efb 100644 --- a/core/embed/trezorhal/stm32u5/limited_util.s +++ b/core/embed/trezorhal/stm32u5/limited_util.S @@ -35,23 +35,14 @@ jump_to: 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 + ldr r0, =_handoff_clear_ram_0_start + ldr r1, =_handoff_clear_ram_0_end 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 + ldr r0, =_handoff_clear_ram_1_start + ldr r1, =_handoff_clear_ram_1_end 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 + ldr r0, =_handoff_clear_ram_2_start + ldr r1, =_handoff_clear_ram_2_end bl memset_reg mov lr, r4 @@ -104,26 +95,17 @@ shutdown_privileged: 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 + ldr r0, =_shutdown_clear_ram_0_start + ldr r1, =_shutdown_clear_ram_0_end 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 + ldr r0, =_shutdown_clear_ram_1_start + ldr r1, =_shutdown_clear_ram_1_end bl memset_reg - ldr r0, =sram3_start // r0 - point to beginning of SRAM - ldr r1, =__fb_start // r1 - point to beginning of framebuffer + ldr r0, =_shutdown_clear_ram_2_start + ldr r1, =_shutdown_clear_ram_2_end 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 + ldr r0, =_shutdown_clear_ram_3_start + ldr r1, =_shutdown_clear_ram_3_end bl memset_reg ldr r0, =1 diff --git a/core/embed/trezorhal/stm32u5/linker/u58/boardloader.ld b/core/embed/trezorhal/stm32u5/linker/u58/boardloader.ld new file mode 100644 index 00000000000..ca7bac1ee69 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/linker/u58/boardloader.ld @@ -0,0 +1,124 @@ +INCLUDE "./embed/trezorhal/stm32u5/linker/u58/memory.ld"; + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = BOARDLOADER_START, LENGTH = BOARDLOADER_IMAGE_MAXSIZE + SRAM1 (wal) : ORIGIN = MCU_SRAM1, LENGTH = MCU_SRAM1_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_SRAM2 - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM2 (wal) : ORIGIN = MCU_SRAM2, LENGTH = MCU_SRAM2_SIZE + SRAM3 (wal) : ORIGIN = MCU_SRAM3, LENGTH = MCU_SRAM3_SIZE + SRAM5 (wal) : ORIGIN = MCU_SRAM5, LENGTH = MCU_SRAM5_SIZE + SRAM6 (wal) : ORIGIN = MCU_SRAM6, LENGTH = MCU_SRAM6_SIZE + SRAM4 (wal) : ORIGIN = MCU_SRAM4, LENGTH = MCU_SRAM4_SIZE +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); + +/* used by the startup code to populate variables used by the C code */ +confidential_lma = LOADADDR(.confidential); +confidential_vma = ADDR(.confidential); +confidential_size = SIZEOF(.confidential); + +/* used by the startup code to wipe memory */ +_startup_clear_ram_0_start = MCU_SRAM1; +_startup_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE - BOOTARGS_SIZE; +_startup_clear_ram_1_start = MCU_SRAM2; +_startup_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_startup_clear_ram_2_start = MCU_SRAM4; +_startup_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_SRAM1; +_handoff_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE - BOOTARGS_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM2; +_handoff_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_handoff_clear_ram_2_start = MCU_SRAM4; +_handoff_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = MCU_SRAM1; +_shutdown_clear_ram_0_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_shutdown_clear_ram_1_start = MCU_SRAM4; +_shutdown_clear_ram_1_end = MCU_SRAM4 + MCU_SRAM4_SIZE; +_shutdown_clear_ram_2_start = 0; +_shutdown_clear_ram_2_end = 0; +_shutdown_clear_ram_3_start = 0; +_shutdown_clear_ram_3_end = 0; + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +SECTIONS { + .vector_table : ALIGN(CODE_ALIGNMENT) { + KEEP(*(.vector_table)); + } >FLASH AT>FLASH + + .text : ALIGN(4) { + *(.text*); + . = ALIGN(4); /* make the section size a multiple of the word size */ + } >FLASH AT>FLASH + + .rodata : ALIGN(4) { + *(.rodata*); + . = ALIGN(4); /* make the section size a multiple of the word size */ + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(8); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .confidential : ALIGN(8) { + *(.confidential*); + . = ALIGN(4); + } >SRAM2 AT>FLASH + + .fb : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.fb2*); + *(.framebuffer_select*); + __fb_end = .; + . = ALIGN(4); + } >SRAM3 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS + + + /* Hard-coded address for capabilities structure */ + .capabilities BOARD_CAPABILITIES_ADDR : {KEEP(*(.capabilities_section))} +} diff --git a/core/embed/bootloader/memory_stm32u58.ld b/core/embed/trezorhal/stm32u5/linker/u58/bootloader.ld similarity index 50% rename from core/embed/bootloader/memory_stm32u58.ld rename to core/embed/trezorhal/stm32u5/linker/u58/bootloader.ld index 0812d1925ca..e46251e96c4 100644 --- a/core/embed/bootloader/memory_stm32u58.ld +++ b/core/embed/trezorhal/stm32u5/linker/u58/bootloader.ld @@ -1,16 +1,16 @@ -/* Trezor v2 bootloader linker script */ +INCLUDE "./embed/trezorhal/stm32u5/linker/u58/memory.ld"; ENTRY(reset_handler) MEMORY { - FLASH (rx) : ORIGIN = 0x0C010000, LENGTH = 128K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 - SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K - SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K - SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ - SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ - SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K + FLASH (rx) : ORIGIN = BOOTLOADER_START, LENGTH = BOOTLOADER_IMAGE_MAXSIZE + SRAM1 (wal) : ORIGIN = MCU_SRAM1, LENGTH = MCU_SRAM1_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_SRAM2 - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM2 (wal) : ORIGIN = MCU_SRAM2, LENGTH = MCU_SRAM2_SIZE + SRAM3 (wal) : ORIGIN = MCU_SRAM3, LENGTH = MCU_SRAM3_SIZE + SRAM5 (wal) : ORIGIN = MCU_SRAM5, LENGTH = MCU_SRAM5_SIZE + SRAM6 (wal) : ORIGIN = MCU_SRAM6, LENGTH = MCU_SRAM6_SIZE + SRAM4 (wal) : ORIGIN = MCU_SRAM4, LENGTH = MCU_SRAM4_SIZE } main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ @@ -21,6 +21,8 @@ _estack = main_stack_base; data_lma = LOADADDR(.data); data_vma = ADDR(.data); data_size = SIZEOF(.data); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* used by the startup code to populate variables used by the C code */ confidential_lma = LOADADDR(.confidential); @@ -28,18 +30,30 @@ confidential_vma = ADDR(.confidential); confidential_size = SIZEOF(.confidential); /* 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); +_startup_clear_ram_0_start = MCU_SRAM1; +_startup_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE - BOOTARGS_SIZE; +_startup_clear_ram_1_start = MCU_SRAM2; +_startup_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_startup_clear_ram_2_start = MCU_SRAM4; +_startup_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_SRAM1; +_handoff_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM2; +_handoff_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_handoff_clear_ram_2_start = MCU_SRAM4; +_handoff_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = MCU_SRAM1; +_shutdown_clear_ram_0_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_shutdown_clear_ram_1_start = MCU_SRAM4; +_shutdown_clear_ram_1_end = MCU_SRAM4 + MCU_SRAM4_SIZE; +_shutdown_clear_ram_2_start = 0; +_shutdown_clear_ram_2_end = 0; +_shutdown_clear_ram_3_start = 0; +_shutdown_clear_ram_3_end = 0; /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); @@ -52,7 +66,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(CODE_ALIGNMENT) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); diff --git a/core/embed/firmware/memory_T3T1.ld b/core/embed/trezorhal/stm32u5/linker/u58/firmware.ld similarity index 50% rename from core/embed/firmware/memory_T3T1.ld rename to core/embed/trezorhal/stm32u5/linker/u58/firmware.ld index 35674f169d5..1542e781ae4 100644 --- a/core/embed/firmware/memory_T3T1.ld +++ b/core/embed/trezorhal/stm32u5/linker/u58/firmware.ld @@ -1,50 +1,34 @@ -/* TREZORv2 firmware linker script */ +INCLUDE "./embed/trezorhal/stm32u5/linker/u58/memory.ld"; ENTRY(reset_handler) MEMORY { - FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 1664K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 - SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K - SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K - SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ - SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ - SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K + FLASH (rx) : ORIGIN = KERNEL_START, LENGTH = FIRMWARE_IMAGE_MAXSIZE + SRAM1 (wal) : ORIGIN = MCU_SRAM1, LENGTH = MCU_SRAM1_SIZE - KERNEL_SRAM1_SIZE + SRAM2 (wal) : ORIGIN = MCU_SRAM2 + KERNEL_SRAM2_SIZE, LENGTH = MCU_SRAM2_SIZE - KERNEL_SRAM2_SIZE + SRAM3 (wal) : ORIGIN = MCU_SRAM3 + KERNEL_SRAM3_SIZE, LENGTH = MCU_SRAM3_SIZE - KERNEL_SRAM3_SIZE + SRAM5 (wal) : ORIGIN = MCU_SRAM5, LENGTH = 0K /* SRAM5 is not available */ + SRAM6 (wal) : ORIGIN = MCU_SRAM6, LENGTH = 0K /* SRAM6 is not available */ + SRAM4 (wal) : ORIGIN = MCU_SRAM4, LENGTH = 0K /* not allocated to coreapp */ } main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ _sstack = ORIGIN(SRAM2); _estack = main_stack_base; +_stack_size = SIZEOF(.stack); /* 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); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* used by the startup code to populate variables used by the C code */ confidential_lma = LOADADDR(.confidential); confidential_vma = ADDR(.confidential); confidential_size = SIZEOF(.confidential); -/* 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); - _codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); _flash_start = ORIGIN(FLASH); _flash_end = ORIGIN(FLASH) + LENGTH(FLASH); @@ -58,17 +42,17 @@ SECTIONS { .header : ALIGN(4) { KEEP(*(.header)); + . = ALIGN(CODE_ALIGNMENT); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(CODE_ALIGNMENT) { + KEEP(*(.kernel)); + . = ALIGN(512); KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); . = ALIGN(4); *(.rodata*); - . = ALIGN(4); - KEEP(*(.bootloader)); - *(.bootloader*); . = ALIGN(512); } >FLASH AT>FLASH @@ -96,15 +80,6 @@ SECTIONS { . = ALIGN(512); } >SRAM2 AT>FLASH - .fb : ALIGN(4) { - __fb_start = .; - *(.fb1*); - *(.fb2*); - *(.framebuffer_select*); - __fb_end = .; - . = ALIGN(4); - } >SRAM3 - .buf : ALIGN(4) { *(.buf*); . = ALIGN(4); @@ -112,13 +87,6 @@ SECTIONS { .heap : ALIGN(4) { . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ - . = ABSOLUTE(sram3_end); /* this explicitly sets the end of the heap */ + . = ABSOLUTE(ORIGIN(SRAM3) + LENGTH(SRAM3)); /* this explicitly sets the end of the heap */ } >SRAM3 - - .boot_args : ALIGN(8) { - *(.boot_command*); - . = ALIGN(8); - *(.boot_args*); - . = ALIGN(8); - } >BOOT_ARGS } diff --git a/core/embed/trezorhal/stm32u5/linker/u58/kernel.ld b/core/embed/trezorhal/stm32u5/linker/u58/kernel.ld new file mode 100644 index 00000000000..2ca5972f28e --- /dev/null +++ b/core/embed/trezorhal/stm32u5/linker/u58/kernel.ld @@ -0,0 +1,162 @@ +INCLUDE "./embed/trezorhal/stm32u5/linker/u58/memory.ld"; + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = KERNEL_START, LENGTH = KERNEL_IMAGE_MAXSIZE + SRAM1 (wal) : ORIGIN = MCU_SRAM2 - KERNEL_SRAM1_SIZE, LENGTH = KERNEL_SRAM1_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_SRAM2 - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM2 (wal) : ORIGIN = MCU_SRAM2, LENGTH = KERNEL_SRAM2_SIZE - KERNEL_U_RAM_SIZE + SRAM2_U (wal) : ORIGIN = MCU_SRAM2 + KERNEL_SRAM2_SIZE - KERNEL_U_RAM_SIZE, LENGTH = KERNEL_U_RAM_SIZE + SRAM3 (wal) : ORIGIN = MCU_SRAM3, LENGTH = KERNEL_SRAM3_SIZE + SRAM5 (wal) : ORIGIN = MCU_SRAM5, LENGTH = 0K /* SRAM5 is not available */ + SRAM6 (wal) : ORIGIN = MCU_SRAM6, LENGTH = 0K /* SRAM6 is not available */ + SRAM4 (wal) : ORIGIN = MCU_SRAM4, LENGTH = MCU_SRAM4_SIZE +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +ustack_base = ORIGIN(SRAM2_U) + 512; +_sustack = ORIGIN(SRAM2_U) + 256; +_eustack = ustack_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); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); + +/* used by the startup code to populate variables used by the C code */ +confidential_lma = LOADADDR(.confidential); +confidential_vma = ADDR(.confidential); +confidential_size = SIZEOF(.confidential); + +/* used by the startup code to wipe memory */ +_startup_clear_ram_0_start = MCU_SRAM1; +_startup_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE; +_startup_clear_ram_1_start = MCU_SRAM2; +_startup_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_startup_clear_ram_2_start = MCU_SRAM4; +_startup_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_SRAM1; +_handoff_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE - BOOTARGS_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM2; +_handoff_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_handoff_clear_ram_2_start = MCU_SRAM4; +_handoff_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = MCU_SRAM1; +_shutdown_clear_ram_0_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_shutdown_clear_ram_1_start = MCU_SRAM4; +_shutdown_clear_ram_1_end = MCU_SRAM4 + MCU_SRAM4_SIZE; +_shutdown_clear_ram_2_start = 0; +_shutdown_clear_ram_2_end = 0; +_shutdown_clear_ram_3_start = 0; +_shutdown_clear_ram_3_end = 0; + +/* used by applet cleaning code */ +_coreapp_clear_ram_0_start = MCU_SRAM2 + KERNEL_SRAM2_SIZE; +_coreapp_clear_ram_0_size = MCU_SRAM2_SIZE - KERNEL_SRAM2_SIZE; +_coreapp_clear_ram_1_start = MCU_SRAM3 + KERNEL_SRAM3_SIZE; +_coreapp_clear_ram_1_size = MCU_SRAM3_SIZE - KERNEL_SRAM3_SIZE; + +sram_u_start = ORIGIN(SRAM2_U); +sram_u_end = ORIGIN(SRAM2_U) + LENGTH(SRAM2_U); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.vendorheader) + SIZEOF(.header) + SIZEOF(.flash) + SIZEOF(.uflash) + SIZEOF(.data) + SIZEOF(.confidential); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); + +_uflash_start = ADDR(.uflash); +_uflash_end = ADDR(.uflash) + SIZEOF(.uflash); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + . = 1K; + . = ALIGN(CODE_ALIGNMENT); + } >FLASH AT>FLASH + + .flash : ALIGN(CODE_ALIGNMENT) { + 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) { + *(.no_dma_buffers*); + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 6K; /* Overflow causes UsageFault */ + } >SRAM2 + + /* unprivileged data and stack for SAES */ + .udata : ALIGN(512) { + *(.udata*); + . = ALIGN(256); + . = 256; /* Overflow causes UsageFault */ + } >SRAM2_U + + .confidential : ALIGN(512) { + *(.confidential*); + . = ALIGN(CODE_ALIGNMENT); + } >SRAM2 AT>FLASH + + .uflash : ALIGN(512) { + *(.uflash*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .fb : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.fb2*); + *(.framebuffer_select*); + __fb_end = .; + . = ALIGN(4); + } >SRAM3 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM3 + + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/trezorhal/stm32u5/linker/u58/memory.ld b/core/embed/trezorhal/stm32u5/linker/u58/memory.ld new file mode 100644 index 00000000000..59826546fa4 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/linker/u58/memory.ld @@ -0,0 +1,18 @@ + + +MCU_FLASH_S_ORIGIN = 0x0C000000; +MCU_FLASH_ORIGIN = 0x08000000; +MCU_FLASH_SIZE = 2M; + +MCU_SRAM1 = 0x30000000; +MCU_SRAM1_SIZE = 192K; +MCU_SRAM2 = 0x30030000; +MCU_SRAM2_SIZE = 64K; +MCU_SRAM3 = 0x30040000; +MCU_SRAM3_SIZE = 512K; +MCU_SRAM4 = 0x38000000; +MCU_SRAM4_SIZE = 16K; +MCU_SRAM5 = 0x30080000; +MCU_SRAM5_SIZE = 0K; /* SRAM5 is not available */ +MCU_SRAM6 = 0x30080000; +MCU_SRAM6_SIZE = 0K ; /* SRAM6 is not available */ diff --git a/core/embed/prodtest/memory_stm32u58.ld b/core/embed/trezorhal/stm32u5/linker/u58/prodtest.ld similarity index 51% rename from core/embed/prodtest/memory_stm32u58.ld rename to core/embed/trezorhal/stm32u5/linker/u58/prodtest.ld index eaa108f73f8..6cabe9cb558 100644 --- a/core/embed/prodtest/memory_stm32u58.ld +++ b/core/embed/trezorhal/stm32u5/linker/u58/prodtest.ld @@ -1,16 +1,16 @@ -/* TREZORv2 firmware linker script */ +INCLUDE "./embed/trezorhal/stm32u5/linker/u58/memory.ld"; ENTRY(reset_handler) MEMORY { - FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 1664K - SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 - BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 - SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K - SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K - SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ - SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ - SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K + FLASH (rx) : ORIGIN = FIRMWARE_START, LENGTH = FIRMWARE_IMAGE_MAXSIZE + SRAM1 (wal) : ORIGIN = MCU_SRAM1, LENGTH = MCU_SRAM1_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_SRAM2 - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM2 (wal) : ORIGIN = MCU_SRAM2, LENGTH = MCU_SRAM2_SIZE + SRAM3 (wal) : ORIGIN = MCU_SRAM3, LENGTH = MCU_SRAM3_SIZE + SRAM5 (wal) : ORIGIN = MCU_SRAM5, LENGTH = MCU_SRAM5_SIZE /* SRAM5 is not available */ + SRAM6 (wal) : ORIGIN = MCU_SRAM6, LENGTH = MCU_SRAM6_SIZE /* SRAM6 is not available */ + SRAM4 (wal) : ORIGIN = MCU_SRAM4, LENGTH = MCU_SRAM4_SIZE } main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ @@ -21,6 +21,9 @@ _estack = main_stack_base; data_lma = LOADADDR(.data); data_vma = ADDR(.data); data_size = SIZEOF(.data); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); + /* used by the startup code to populate variables used by the C code */ confidential_lma = LOADADDR(.confidential); @@ -28,18 +31,30 @@ confidential_vma = ADDR(.confidential); confidential_size = SIZEOF(.confidential); /* 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); +_startup_clear_ram_0_start = MCU_SRAM1; +_startup_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE; +_startup_clear_ram_1_start = MCU_SRAM2; +_startup_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_startup_clear_ram_2_start = MCU_SRAM4; +_startup_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_SRAM1; +_handoff_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE - BOOTARGS_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM2; +_handoff_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_handoff_clear_ram_2_start = MCU_SRAM4; +_handoff_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = MCU_SRAM1; +_shutdown_clear_ram_0_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_shutdown_clear_ram_1_start = MCU_SRAM4; +_shutdown_clear_ram_1_end = MCU_SRAM4 + MCU_SRAM4_SIZE; +_shutdown_clear_ram_2_start = 0; +_shutdown_clear_ram_2_end = 0; +_shutdown_clear_ram_3_start = 0; +_shutdown_clear_ram_3_end = 0; /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); @@ -48,8 +63,6 @@ boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); _codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); _flash_start = ORIGIN(FLASH); _flash_end = ORIGIN(FLASH) + LENGTH(FLASH); -_heap_start = ADDR(.heap); -_heap_end = ADDR(.heap) + SIZEOF(.heap); SECTIONS { .vendorheader : ALIGN(4) { @@ -60,7 +73,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(CODE_ALIGNMENT) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); @@ -82,20 +95,11 @@ SECTIONS { } .bss : ALIGN(4) { - *(.bss*); - . = ALIGN(4); - } >SRAM1 - - .data_ccm : ALIGN(4) { *(.no_dma_buffers*); + *(.bss*); . = 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; /* Overflow causes UsageFault */ } >SRAM2 @@ -109,7 +113,6 @@ SECTIONS { __fb_start = .; *(.fb1*); *(.fb2*); - *(.framebuffer_select*); __fb_end = .; . = ALIGN(4); } >SRAM3 diff --git a/core/embed/trezorhal/stm32u5/linker/u5a/boardloader.ld b/core/embed/trezorhal/stm32u5/linker/u5a/boardloader.ld new file mode 100644 index 00000000000..6c455e2641c --- /dev/null +++ b/core/embed/trezorhal/stm32u5/linker/u5a/boardloader.ld @@ -0,0 +1,127 @@ +INCLUDE "./embed/trezorhal/stm32u5/linker/u5a/memory.ld"; + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = BOARDLOADER_START, LENGTH = BOARDLOADER_IMAGE_MAXSIZE + SRAM1 (wal) : ORIGIN = MCU_SRAM1, LENGTH = MCU_SRAM1_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_SRAM2 - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM2 (wal) : ORIGIN = MCU_SRAM2, LENGTH = MCU_SRAM2_SIZE + SRAM3 (wal) : ORIGIN = MCU_SRAM3, LENGTH = MCU_SRAM3_SIZE + SRAM5 (wal) : ORIGIN = MCU_SRAM5, LENGTH = MCU_SRAM5_SIZE + SRAM6 (wal) : ORIGIN = MCU_SRAM6, LENGTH = MCU_SRAM6_SIZE + SRAM4 (wal) : ORIGIN = MCU_SRAM4, LENGTH = MCU_SRAM4_SIZE +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); + +/* used by the startup code to populate variables used by the C code */ +confidential_lma = LOADADDR(.confidential); +confidential_vma = ADDR(.confidential); +confidential_size = SIZEOF(.confidential); + +/* used by the startup code to wipe memory */ +_startup_clear_ram_0_start = MCU_SRAM1; +_startup_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE - BOOTARGS_SIZE; +_startup_clear_ram_1_start = MCU_SRAM2; +_startup_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_startup_clear_ram_2_start = MCU_SRAM4; +_startup_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_SRAM1; +_handoff_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE - BOOTARGS_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM2; +_handoff_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_handoff_clear_ram_2_start = MCU_SRAM4; +_handoff_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = ORIGIN(SRAM1); +_shutdown_clear_ram_0_end = ADDR(.fb1); +_shutdown_clear_ram_1_start = ADDR(.fb1) + SIZEOF(.fb1); +_shutdown_clear_ram_1_end = ADDR(.fb2); +_shutdown_clear_ram_2_start = ADDR(.fb2) + SIZEOF(.fb2); +_shutdown_clear_ram_2_end = ORIGIN(SRAM6)+ LENGTH(SRAM6); +_shutdown_clear_ram_3_start = ORIGIN(SRAM4); +_shutdown_clear_ram_3_end = ORIGIN(SRAM4) + LENGTH(SRAM4); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +SECTIONS { + .vector_table : ALIGN(CODE_ALIGNMENT) { + 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); + } >SRAM5 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM5 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM5 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .confidential : ALIGN(8) { + *(.confidential*); + . = ALIGN(4); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + *(.fb1*); + . = ALIGN(4); + } >SRAM1 + + .fb2 : ALIGN(4) { + *(.fb2*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS + + + /* Hard-coded address for capabilities structure */ + .capabilities BOARD_CAPABILITIES_ADDR : {KEEP(*(.capabilities_section))} +} diff --git a/core/embed/trezorhal/stm32u5/linker/u5a/bootloader.ld b/core/embed/trezorhal/stm32u5/linker/u5a/bootloader.ld new file mode 100644 index 00000000000..e031a7062a8 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/linker/u5a/bootloader.ld @@ -0,0 +1,128 @@ +INCLUDE "./embed/trezorhal/stm32u5/linker/u5a/memory.ld"; + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = BOOTLOADER_START, LENGTH = BOOTLOADER_IMAGE_MAXSIZE + SRAM1 (wal) : ORIGIN = MCU_SRAM1, LENGTH = MCU_SRAM1_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_SRAM2 - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM2 (wal) : ORIGIN = MCU_SRAM2, LENGTH = MCU_SRAM2_SIZE + SRAM3 (wal) : ORIGIN = MCU_SRAM3, LENGTH = MCU_SRAM3_SIZE + SRAM5 (wal) : ORIGIN = MCU_SRAM5, LENGTH = MCU_SRAM5_SIZE + SRAM6 (wal) : ORIGIN = MCU_SRAM6, LENGTH = MCU_SRAM6_SIZE + SRAM4 (wal) : ORIGIN = MCU_SRAM4, LENGTH = MCU_SRAM4_SIZE +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); + +/* used by the startup code to populate variables used by the C code */ +confidential_lma = LOADADDR(.confidential); +confidential_vma = ADDR(.confidential); +confidential_size = SIZEOF(.confidential); + +/* used by the startup code to wipe memory */ +_startup_clear_ram_0_start = MCU_SRAM1; +_startup_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE - BOOTARGS_SIZE; +_startup_clear_ram_1_start = MCU_SRAM2; +_startup_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_startup_clear_ram_2_start = MCU_SRAM4; +_startup_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_SRAM1; +_handoff_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM2; +_handoff_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_handoff_clear_ram_2_start = MCU_SRAM4; +_handoff_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = ORIGIN(SRAM1); +_shutdown_clear_ram_0_end = ADDR(.fb1); +_shutdown_clear_ram_1_start = ADDR(.fb1) + SIZEOF(.fb1); +_shutdown_clear_ram_1_end = ADDR(.fb2); +_shutdown_clear_ram_2_start = ADDR(.fb2) + SIZEOF(.fb2); +_shutdown_clear_ram_2_end = ORIGIN(SRAM6)+ LENGTH(SRAM6); +_shutdown_clear_ram_3_start = ORIGIN(SRAM4); +_shutdown_clear_ram_3_end = ORIGIN(SRAM4) + LENGTH(SRAM4); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); + +SECTIONS { + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(CODE_ALIGNMENT) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM5 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM5 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + *(.no_dma_buffers*); + . = ALIGN(4); + } >SRAM5 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .confidential : ALIGN(512) { + *(.confidential*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + . = ALIGN(4); + } >SRAM1 + + .fb2 : ALIGN(4) { + *(.fb2*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + __fb_end = .; + . = ALIGN(4); + } >SRAM3 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/trezorhal/stm32u5/linker/u5a/firmware.ld b/core/embed/trezorhal/stm32u5/linker/u5a/firmware.ld new file mode 100644 index 00000000000..73af99e7050 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/linker/u5a/firmware.ld @@ -0,0 +1,92 @@ +INCLUDE "./embed/trezorhal/stm32u5/linker/u5a/memory.ld"; + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = KERNEL_START, LENGTH = FIRMWARE_IMAGE_MAXSIZE + SRAM1 (wal) : ORIGIN = MCU_SRAM1, LENGTH = 0K /* not allocated to coreapp */ + SRAM2 (wal) : ORIGIN = MCU_SRAM2, LENGTH = 0K /* not allocated to coreapp */ + SRAM3 (wal) : ORIGIN = MCU_SRAM3, LENGTH = 0K /* not allocated to coreapp */ + SRAM5 (wal) : ORIGIN = MCU_SRAM5, LENGTH = MCU_SRAM5_SIZE + SRAM6 (wal) : ORIGIN = MCU_SRAM6, LENGTH = 0K /* not allocated to coreapp */ + SRAM4 (wal) : ORIGIN = MCU_SRAM4, LENGTH = 0K /* not allocated to coreapp */ +} + +main_stack_base = ORIGIN(SRAM5) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM5); +_estack = main_stack_base; +_stack_size = SIZEOF(.stack); + +/* 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); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); + +/* used by the startup code to populate variables used by the C code */ +confidential_lma = LOADADDR(.confidential); +confidential_vma = ADDR(.confidential); +confidential_size = SIZEOF(.confidential); + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); +_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(CODE_ALIGNMENT) { + KEEP(*(.kernel)); + . = ALIGN(512); + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .stack : ALIGN(8) { + . = 32K; /* Overflow causes UsageFault */ + } >SRAM5 + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM5 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.no_dma_buffers*); + *(.bss*); + . = ALIGN(4); + } >SRAM5 + + .confidential : ALIGN(512) { + *(.confidential*); + . = ALIGN(512); + } >SRAM5 AT>FLASH + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM5 + + .heap : ALIGN(4) { + . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ + . = ABSOLUTE(ORIGIN(SRAM5) + LENGTH(SRAM5)); /* this explicitly sets the end of the heap */ + } >SRAM5 + +} diff --git a/core/embed/trezorhal/stm32u5/linker/u5a/kernel.ld b/core/embed/trezorhal/stm32u5/linker/u5a/kernel.ld new file mode 100644 index 00000000000..31c7652ccf3 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/linker/u5a/kernel.ld @@ -0,0 +1,166 @@ +INCLUDE "./embed/trezorhal/stm32u5/linker/u5a/memory.ld"; + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = KERNEL_START, LENGTH = KERNEL_IMAGE_MAXSIZE + SRAM1 (wal) : ORIGIN = MCU_SRAM1, LENGTH = MCU_SRAM1_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_SRAM2 - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM2 (wal) : ORIGIN = MCU_SRAM2, LENGTH = MCU_SRAM2_SIZE + SRAM3 (wal) : ORIGIN = MCU_SRAM3, LENGTH = MCU_SRAM3_SIZE - KERNEL_U_RAM_SIZE + SRAM3_U (wal) : ORIGIN = MCU_SRAM3 + MCU_SRAM3_SIZE - KERNEL_U_RAM_SIZE, LENGTH = KERNEL_U_RAM_SIZE + SRAM5 (wal) : ORIGIN = MCU_SRAM5, LENGTH = MCU_SRAM5_SIZE + SRAM6 (wal) : ORIGIN = MCU_SRAM6, LENGTH = MCU_SRAM6_SIZE + SRAM4 (wal) : ORIGIN = MCU_SRAM4, LENGTH = MCU_SRAM4_SIZE +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +ustack_base = ORIGIN(SRAM3_U) + 512; +_sustack = ORIGIN(SRAM3_U) + 256; +_eustack = ustack_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); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); + +/* used by the startup code to populate variables used by the C code */ +confidential_lma = LOADADDR(.confidential); +confidential_vma = ADDR(.confidential); +confidential_size = SIZEOF(.confidential); + +/* used by the startup code to wipe memory */ +_startup_clear_ram_0_start = MCU_SRAM1; +_startup_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE; +_startup_clear_ram_1_start = MCU_SRAM2; +_startup_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_startup_clear_ram_2_start = MCU_SRAM4; +_startup_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_SRAM1; +_handoff_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE - BOOTARGS_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM2; +_handoff_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_handoff_clear_ram_2_start = MCU_SRAM4; +_handoff_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = ORIGIN(SRAM1); +_shutdown_clear_ram_0_end = ADDR(.fb1); +_shutdown_clear_ram_1_start = ADDR(.fb1) + SIZEOF(.fb1); +_shutdown_clear_ram_1_end = ADDR(.fb2); +_shutdown_clear_ram_2_start = ADDR(.fb2) + SIZEOF(.fb2); +_shutdown_clear_ram_2_end = ORIGIN(SRAM6)+ LENGTH(SRAM6); +_shutdown_clear_ram_3_start = ORIGIN(SRAM4); +_shutdown_clear_ram_3_end = ORIGIN(SRAM4) + LENGTH(SRAM4); + +/* used by appleet cleaning code */ +_coreapp_clear_ram_0_start = MCU_SRAM5; +_coreapp_clear_ram_0_size = MCU_SRAM5_SIZE; +_coreapp_clear_ram_1_start = 0; +_coreapp_clear_ram_1_size = 0; + + +sram_u_start = ORIGIN(SRAM3_U); +sram_u_end = ORIGIN(SRAM3_U) + LENGTH(SRAM3_U); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.vendorheader) + SIZEOF(.header) + SIZEOF(.flash) + SIZEOF(.uflash) + SIZEOF(.data) + SIZEOF(.confidential); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); + +_uflash_start = ADDR(.uflash); +_uflash_end = ADDR(.uflash) + SIZEOF(.uflash); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + . = 1K; + . = ALIGN(CODE_ALIGNMENT); + } >FLASH AT>FLASH + + .flash : ALIGN(CODE_ALIGNMENT) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .stack : ALIGN(8) { + . = 12K; /* Overflow causes UsageFault */ + } >SRAM2 + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.no_dma_buffers*); + *(.bss*); + . = ALIGN(4); + } >SRAM2 + + /* unprivileged data and stack for SAES */ + .udata : ALIGN(512) { + *(.udata*); + . = ALIGN(256); + . = 256; /* Overflow causes UsageFault */ + } >SRAM3_U + + .confidential : ALIGN(512) { + *(.confidential*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .uflash : ALIGN(512) { + *(.uflash*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .fb1 : ALIGN(4) { + *(.fb1*); + . = ALIGN(4); + } >SRAM1 + + .fb2 : ALIGN(4) { + *(.fb2*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM2 + + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/trezorhal/stm32u5/linker/u5a/memory.ld b/core/embed/trezorhal/stm32u5/linker/u5a/memory.ld new file mode 100644 index 00000000000..157833f9654 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/linker/u5a/memory.ld @@ -0,0 +1,18 @@ + + +MCU_FLASH_S_ORIGIN = 0x0C000000; +MCU_FLASH_ORIGIN = 0x08000000; +MCU_FLASH_SIZE = 4M; + +MCU_SRAM1 = 0x30000000; +MCU_SRAM1_SIZE = 768K; +MCU_SRAM2 = 0x300C0000; +MCU_SRAM2_SIZE = 64K; +MCU_SRAM3 = 0x300D0000; +MCU_SRAM3_SIZE = 832K; +MCU_SRAM4 = 0x38000000; +MCU_SRAM4_SIZE = 16K; +MCU_SRAM5 = 0x301A0000; +MCU_SRAM5_SIZE = 832K; +MCU_SRAM6 = 0x30270000; +MCU_SRAM6_SIZE = 0K ; diff --git a/core/embed/trezorhal/stm32u5/linker/u5a/prodtest.ld b/core/embed/trezorhal/stm32u5/linker/u5a/prodtest.ld new file mode 100644 index 00000000000..9fc58c604e9 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/linker/u5a/prodtest.ld @@ -0,0 +1,136 @@ +INCLUDE "./embed/trezorhal/stm32u5/linker/u5a/memory.ld"; + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = KERNEL_START, LENGTH = KERNEL_IMAGE_MAXSIZE + SRAM1 (wal) : ORIGIN = MCU_SRAM1, LENGTH = MCU_SRAM1_SIZE - BOOTARGS_SIZE + BOOT_ARGS (wal) : ORIGIN = MCU_SRAM2 - BOOTARGS_SIZE, LENGTH = BOOTARGS_SIZE + SRAM2 (wal) : ORIGIN = MCU_SRAM2, LENGTH = MCU_SRAM2_SIZE + SRAM3 (wal) : ORIGIN = MCU_SRAM3, LENGTH = MCU_SRAM3_SIZE + SRAM5 (wal) : ORIGIN = MCU_SRAM5, LENGTH = MCU_SRAM5_SIZE + SRAM6 (wal) : ORIGIN = MCU_SRAM6, LENGTH = MCU_SRAM6_SIZE + SRAM4 (wal) : ORIGIN = MCU_SRAM4, LENGTH = MCU_SRAM4_SIZE +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); + +/* used by the startup code to populate variables used by the C code */ +confidential_lma = LOADADDR(.confidential); +confidential_vma = ADDR(.confidential); +confidential_size = SIZEOF(.confidential); + +/* used by the startup code to wipe memory */ +_startup_clear_ram_0_start = MCU_SRAM1; +_startup_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE; +_startup_clear_ram_1_start = MCU_SRAM2; +_startup_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_startup_clear_ram_2_start = MCU_SRAM4; +_startup_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the jump code to wipe memory */ +_handoff_clear_ram_0_start = MCU_SRAM1; +_handoff_clear_ram_0_end = MCU_SRAM1 + MCU_SRAM1_SIZE - BOOTARGS_SIZE; +_handoff_clear_ram_1_start = MCU_SRAM2; +_handoff_clear_ram_1_end = MCU_SRAM6 + MCU_SRAM6_SIZE; +_handoff_clear_ram_2_start = MCU_SRAM4; +_handoff_clear_ram_2_end = MCU_SRAM4 + MCU_SRAM4_SIZE; + +/* used by the shutdown code to wipe memory */ +_shutdown_clear_ram_0_start = ORIGIN(SRAM1); +_shutdown_clear_ram_0_end = ADDR(.fb1); +_shutdown_clear_ram_1_start = ADDR(.fb1) + SIZEOF(.fb1); +_shutdown_clear_ram_1_end = ADDR(.fb2); +_shutdown_clear_ram_2_start = ADDR(.fb2) + SIZEOF(.fb2); +_shutdown_clear_ram_2_end = ORIGIN(SRAM6)+ LENGTH(SRAM6); +_shutdown_clear_ram_3_start = ORIGIN(SRAM4); +_shutdown_clear_ram_3_end = ORIGIN(SRAM4) + LENGTH(SRAM4); + + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.confidential); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + KEEP(*(.header)); + . = ALIGN(CODE_ALIGNMENT); + } >FLASH AT>FLASH + + .flash : ALIGN(CODE_ALIGNMENT) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .stack : ALIGN(8) { + . = 12K; /* Overflow causes UsageFault */ + } >SRAM2 + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.no_dma_buffers*); + *(.bss*); + . = ALIGN(4); + } >SRAM2 + + .confidential : ALIGN(512) { + *(.confidential*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + *(.fb1*); + . = ALIGN(4); + } >SRAM1 + + .fb2 : ALIGN(4) { + *(.fb2*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM2 + + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/trezorhal/stm32u5/lowlevel.c b/core/embed/trezorhal/stm32u5/lowlevel.c index e30aa526739..7270180782d 100644 --- a/core/embed/trezorhal/stm32u5/lowlevel.c +++ b/core/embed/trezorhal/stm32u5/lowlevel.c @@ -19,6 +19,8 @@ #include STM32_HAL_H +#ifdef KERNEL_MODE + #include "lowlevel.h" #include "common.h" #include "flash.h" @@ -310,3 +312,5 @@ secbool reset_flags_check(void) { void reset_flags_reset(void) { RCC->CSR |= RCC_CSR_RMVF; // clear the reset flags } + +#endif // #ifdef KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/monoctr.c b/core/embed/trezorhal/stm32u5/monoctr.c index 6504371fa26..f44711b4ad2 100644 --- a/core/embed/trezorhal/stm32u5/monoctr.c +++ b/core/embed/trezorhal/stm32u5/monoctr.c @@ -20,8 +20,11 @@ #include "monoctr.h" #include "flash_area.h" #include "model.h" +#include "mpu.h" #include "secret.h" +#ifdef KERNEL_MODE + static int32_t get_offset(monoctr_type_t type) { switch (type) { case MONOCTR_BOOTLOADER_VERSION: @@ -80,6 +83,8 @@ secbool monoctr_read(monoctr_type_t type, uint8_t *value) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + int counter = 0; int i = 0; @@ -111,10 +116,13 @@ secbool monoctr_read(monoctr_type_t type, uint8_t *value) { if (not_cleared != sectrue) { // monotonic counter is not valid + mpu_restore(mpu_mode); return secfalse; } } + mpu_restore(mpu_mode); + if (value != NULL) { *value = counter; } else { @@ -123,3 +131,5 @@ secbool monoctr_read(monoctr_type_t type, uint8_t *value) { return sectrue; } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/mpu.c b/core/embed/trezorhal/stm32u5/mpu.c index 25c04d5e13b..7cdd1894878 100644 --- a/core/embed/trezorhal/stm32u5/mpu.c +++ b/core/embed/trezorhal/stm32u5/mpu.c @@ -19,10 +19,16 @@ #include STM32_HAL_H #include + #include "common.h" +#include "irq.h" #include "model.h" +#include "mpu.h" + #include "stm32u5xx_ll_cortex.h" +#ifdef KERNEL_MODE + // region type #define MPUX_TYPE_FLASH_CODE 0 #define MPUX_TYPE_SRAM 1 @@ -109,7 +115,7 @@ static void mpu_set_attributes(void) { #define SECRET_START FLASH_BASE #define SECRET_SIZE SIZE_16K -#define BOARDLOADER_SIZE SIZE_48K +#define BOARDLOADER_SIZE BOARDLOADER_IMAGE_MAXSIZE #define BOOTLOADER_SIZE BOOTLOADER_IMAGE_MAXSIZE #define FIRMWARE_SIZE FIRMWARE_IMAGE_MAXSIZE #define STORAGE_START \ @@ -117,31 +123,20 @@ static void mpu_set_attributes(void) { #define STORAGE_SIZE NORCOW_SECTOR_SIZE* STORAGE_AREAS_COUNT #if defined STM32U5A9xx -#define SRAM_SIZE SIZE_2496K +#define SRAM_SIZE SRAM1_SIZE + SRAM2_SIZE + SRAM3_SIZE + SRAM5_SIZE #elif defined STM32U5G9xx -#define SRAM_SIZE (SIZE_2496K + SIZE_512K) +#define SRAM_SIZE SRAM1_SIZE + SRAM2_SIZE + SRAM3_SIZE + SRAM5_SIZE + SRAM6_SIZE #elif defined STM32U585xx -#define SRAM_SIZE SIZE_768K +#define SRAM_SIZE SRAM1_SIZE + SRAM2_SIZE + SRAM3_SIZE #else #error "Unknown MCU" #endif -#define L1_REST_SIZE (FLASH_SIZE - (BOARDLOADER_SIZE + SECRET_SIZE)) - -#define L2_PREV_SIZE (SECRET_SIZE + BOARDLOADER_SIZE) -#define L2_REST_SIZE \ - (FLASH_SIZE - (BOOTLOADER_SIZE + BOARDLOADER_SIZE + SECRET_SIZE)) - -#define L3_PREV_SIZE \ - (STORAGE_SIZE + BOOTLOADER_SIZE + BOARDLOADER_SIZE + SECRET_SIZE) - #define ASSETS_START (FIRMWARE_START + FIRMWARE_SIZE) #define ASSETS_SIZE \ (FLASH_SIZE - (FIRMWARE_SIZE + BOOTLOADER_SIZE + BOARDLOADER_SIZE + \ SECRET_SIZE + STORAGE_SIZE)) -#define L3_PREV_SIZE_BLD (STORAGE_SIZE + BOOTLOADER_SIZE) - #ifdef STM32U585xx #define GRAPHICS_START FMC_BANK1 #define GRAPHICS_SIZE SIZE_16M @@ -152,106 +147,250 @@ static void mpu_set_attributes(void) { #define OTP_AND_ID_SIZE 0x800 -void mpu_config_boardloader(void) { - HAL_MPU_Disable(); - mpu_set_attributes(); +// clang-format on + +#ifdef STM32U585xx +#define KERNEL_RAM_START (SRAM2_BASE - KERNEL_SRAM1_SIZE) +#define KERNEL_RAM_SIZE \ + ((KERNEL_SRAM1_SIZE + KERNEL_SRAM2_SIZE) - KERNEL_U_RAM_SIZE) +#else +#define KERNEL_RAM_START (SRAM1_BASE) +#define KERNEL_RAM_SIZE \ + (SRAM1_SIZE + SRAM2_SIZE + SRAM3_SIZE - KERNEL_U_RAM_SIZE) +#endif + +#ifdef SYSCALL_DISPATCH +extern uint32_t _uflash_start; +extern uint32_t _uflash_end; +#define KERNEL_RAM_U_START (KERNEL_RAM_START + KERNEL_RAM_SIZE) +#define KERNEL_RAM_U_SIZE KERNEL_U_RAM_SIZE +#define KERNEL_FLASH_U_START (uint32_t) & _uflash_start +#define KERNEL_FLASH_U_SIZE ((uint32_t) & _uflash_end - KERNEL_FLASH_U_START) +#else +#define KERNEL_RAM_U_START 0 +#define KERNEL_RAM_U_SIZE 0 +#define KERNEL_FLASH_U_START 0 +#define KERNEL_FLASH_U_SIZE 0 +#endif + +extern uint32_t _codelen; +#define KERNEL_SIZE (uint32_t) & _codelen + +#define KERNEL_FLASH_START KERNEL_START +#define KERNEL_FLASH_SIZE (KERNEL_SIZE - KERNEL_U_FLASH_SIZE) + +#define COREAPP_FLASH_START (KERNEL_FLASH_START + KERNEL_SIZE) +#define COREAPP_FLASH_SIZE (FIRMWARE_IMAGE_MAXSIZE - KERNEL_SIZE) + +#ifdef STM32U585xx +#define COREAPP_RAM1_START SRAM1_BASE +#define COREAPP_RAM1_SIZE (SRAM1_SIZE - KERNEL_SRAM1_SIZE) + +#define COREAPP_RAM2_START (SRAM2_BASE + KERNEL_SRAM2_SIZE) +#define COREAPP_RAM2_SIZE (SRAM_SIZE - (SRAM1_SIZE + KERNEL_SRAM2_SIZE)) +#else +#define COREAPP_RAM1_START SRAM5_BASE +#define COREAPP_RAM1_SIZE SRAM5_SIZE +#endif + +typedef struct { + // Set if the driver is initialized + bool initialized; + // Current mode + mpu_mode_t mode; + +} mpu_driver_t; + +mpu_driver_t g_mpu_driver = { + .initialized = false, + .mode = MPU_MODE_DISABLED, +}; + +static void mpu_init_fixed_regions(void) { + // Regions #0 to #5 are fixed for all targets + // clang-format off +#if defined(BOARDLOADER) + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, BOARDLOADER_START, BOARDLOADER_SIZE, FLASH_CODE, NO, NO ); + SET_REGION( 1, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); + SET_REGION( 2, BOOTLOADER_START, BOOTLOADER_SIZE, FLASH_DATA, YES, NO ); + SET_REGION( 3, FIRMWARE_START, FIRMWARE_SIZE, FLASH_DATA, YES, NO ); + DIS_REGION( 4 ); +#endif +#if defined(BOOTLOADER) // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, SECRET_START, SECRET_SIZE, FLASH_DATA, YES, NO ); // Secret - SET_REGION( 1, BOARDLOADER_START, BOARDLOADER_SIZE, FLASH_CODE, NO, NO ); // Boardloader code - SET_REGION( 2, BOOTLOADER_START, L1_REST_SIZE, FLASH_DATA, YES, NO ); // Bootloader + Storage + Firmware - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, NO ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, NO ); // Peripherals + SET_REGION( 0, BOOTLOADER_START, BOOTLOADER_SIZE, FLASH_CODE, NO, NO ); + SET_REGION( 1, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); + SET_REGION( 2, FIRMWARE_START, FIRMWARE_SIZE, FLASH_DATA, YES, NO ); + DIS_REGION( 3 ); + DIS_REGION( 4 ); +#endif +#if defined(KERNEL) + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, KERNEL_FLASH_START, KERNEL_FLASH_SIZE, FLASH_CODE, NO, NO ); // Kernel Code + SET_REGION( 1, KERNEL_RAM_START, KERNEL_RAM_SIZE, SRAM, YES, NO ); // Kernel RAM + SET_REGION( 2, COREAPP_FLASH_START, COREAPP_FLASH_SIZE, FLASH_CODE, NO, YES ); // CoreApp Code + SET_REGION( 3, COREAPP_RAM1_START, COREAPP_RAM1_SIZE, SRAM, YES, YES ); // CoraApp RAM +#ifdef STM32U585xx + SET_REGION( 4, COREAPP_RAM2_START, COREAPP_RAM2_SIZE, SRAM, YES, YES ); // CoraAPP RAM2 +#else + DIS_REGION( 4 ); +#endif +#endif +#if defined(FIRMWARE) + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, NO ); + SET_REGION( 1, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); + DIS_REGION( 2 ); + DIS_REGION( 3 ); + DIS_REGION( 4 ); +#endif +#if defined(TREZOR_PRODTEST) + SET_REGION( 0, FIRMWARE_START, 1024, FLASH_DATA, YES, NO ); + SET_REGION( 1, FIRMWARE_START + 1024, FIRMWARE_SIZE - 1024, FLASH_CODE, NO, NO ); + SET_REGION( 2, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); + DIS_REGION( 3 ); + DIS_REGION( 4 ); +#endif + + // Regions #6 and #7 are banked + + DIS_REGION( 5 ); DIS_REGION( 6 ); - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, NO ); // SRAM4 + DIS_REGION( 7 ); // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); } -void mpu_config_bootloader(void) { +void mpu_init(void) { + mpu_driver_t* drv = &g_mpu_driver; + + if (drv->initialized) { + return; + } + + irq_key_t irq_key = irq_lock(); + HAL_MPU_Disable(); + mpu_set_attributes(); - // clang-format off - // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, SECRET_START, L2_PREV_SIZE, FLASH_DATA, YES, NO ); // Secret + Boardloader - SET_REGION( 1, BOOTLOADER_START, BOOTLOADER_SIZE, FLASH_CODE, NO, NO ); // Bootloader code - SET_REGION( 2, STORAGE_START, L2_REST_SIZE, FLASH_DATA, YES, NO ); // Storage + Firmware - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, NO ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, NO ); // Peripherals - SET_REGION( 6, FLASH_OTP_BASE, FLASH_OTP_SIZE, FLASH_DATA, YES, NO ); // OTP - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, NO ); // SRAM4 - // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + + mpu_init_fixed_regions(); + + drv->mode = MPU_MODE_DISABLED; + drv->initialized = true; + + irq_unlock(irq_key); } -void mpu_config_firmware_initial(void) { - HAL_MPU_Disable(); - mpu_set_attributes(); - // clang-format off - // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, BOOTLOADER_START, L3_PREV_SIZE_BLD, FLASH_DATA, YES, YES ); // Bootloader + Storage - SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, YES ); // Firmware - SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals - SET_REGION( 6, FLASH_OTP_BASE, SIZE_2K, FLASH_DATA, YES, YES ); // OTP - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 - // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); +mpu_mode_t mpu_get_mode(void) { + mpu_driver_t* drv = &g_mpu_driver; + + if (!drv->initialized) { + return MPU_MODE_DISABLED; + } + + return drv->mode; } -void mpu_config_firmware(void) { +mpu_mode_t mpu_reconfig(mpu_mode_t mode) { + mpu_driver_t* drv = &g_mpu_driver; + + if (!drv->initialized) { + // Solves the issue when some IRQ handler tries to reconfigure + // MPU before it is initialized + return MPU_MODE_DISABLED; + } + + irq_key_t irq_key = irq_lock(); + HAL_MPU_Disable(); - mpu_set_attributes(); + + // Region #5 is banked + // clang-format off - // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, STORAGE_START, STORAGE_SIZE, FLASH_DATA, YES, YES ); // Storage - SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, YES ); // Firmware - SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals - SET_REGION( 6, FLASH_OTP_BASE, FLASH_OTP_SIZE, FLASH_DATA, YES, YES ); // OTP - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 + switch (mode) { + case MPU_MODE_SAES: + SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals - SAES, TAMP + break; + default: + SET_REGION( 5, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface + break; + } // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); -} -void mpu_config_prodtest_initial(void) { - HAL_MPU_Disable(); - mpu_set_attributes(); + // Region #6 is banked + // clang-format off - // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, FLASH_BASE, L3_PREV_SIZE, FLASH_DATA, YES, YES ); // Secret, Bld, Storage - SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, YES ); // Firmware - SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals - SET_REGION( 6, FLASH_OTP_BASE, FLASH_OTP_SIZE, FLASH_DATA, YES, YES ); // OTP - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 + switch (mode) { + case MPU_MODE_DISABLED: + break; +#if !defined(BOARDLOADER) + case MPU_MODE_BOARDCAPS: + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 6, BOARDLOADER_START, BOARDLOADER_SIZE, FLASH_DATA, NO, NO ); + break; +#endif +#if !defined(BOOTLOADER) && !defined(BOARDLOADER) + case MPU_MODE_BOOTUPDATE: + SET_REGION( 6, BOOTLOADER_START, BOOTLOADER_SIZE, FLASH_DATA, YES, NO ); + break; +#endif + case MPU_MODE_OTP: + SET_REGION( 6, FLASH_OTP_BASE, OTP_AND_ID_SIZE, FLASH_DATA, NO, NO ); + break; + case MPU_MODE_SECRET: + SET_REGION( 6, SECRET_START, SECRET_SIZE, FLASH_DATA, YES, NO ); + break; + case MPU_MODE_STORAGE: + SET_REGION( 6, STORAGE_START, STORAGE_SIZE, FLASH_DATA, YES, NO ); + break; + case MPU_MODE_ASSETS: + SET_REGION( 6, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, NO ); + break; + case MPU_MODE_SAES: + SET_REGION( 6, KERNEL_FLASH_U_START, KERNEL_FLASH_U_SIZE,FLASH_CODE, NO, YES ); // Unprivileged kernal flash + break; + case MPU_MODE_APP: + SET_REGION( 6, ASSETS_START, ASSETS_SIZE, FLASH_DATA, NO, YES ); + break; + default: + DIS_REGION( 6 ); + break; + } // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); -} -void mpu_config_prodtest(void) { - HAL_MPU_Disable(); - mpu_set_attributes(); + // Region #7 is banked + // clang-format off - // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, STORAGE_START, STORAGE_SIZE, FLASH_DATA, YES, YES ); // Storage - SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, YES, YES ); // Firmware - SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals - SET_REGION( 6, FLASH_OTP_BASE, OTP_AND_ID_SIZE, FLASH_DATA, YES, YES ); // OTP + device ID - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 + switch (mode) { + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + case MPU_MODE_SAES: + SET_REGION( 7, KERNEL_RAM_U_START, KERNEL_RAM_U_SIZE, SRAM, YES, YES ); // Unprivileged kernel SRAM + break; + case MPU_MODE_APP: + // DMA2D peripherals (Unprivileged, Read-Write, Non-Executable) + SET_REGION( 7, 0x5002B000, SIZE_3K, PERIPHERAL, YES, YES ); + break; + default: + // All peripherals (Privileged, Read-Write, Non-Executable) + SET_REGION( 7, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, NO ); + break; + } // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + + if (mode != MPU_MODE_DISABLED) { + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + } + + mpu_mode_t prev_mode = drv->mode; + drv->mode = mode; + + irq_unlock(irq_key); + + return prev_mode; } -void mpu_config_off(void) { HAL_MPU_Disable(); } +void mpu_restore(mpu_mode_t mode) { mpu_reconfig(mode); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/platform.c b/core/embed/trezorhal/stm32u5/platform.c index fd31a29e2b2..393a43b5303 100644 --- a/core/embed/trezorhal/stm32u5/platform.c +++ b/core/embed/trezorhal/stm32u5/platform.c @@ -23,6 +23,8 @@ #include "rng.h" #include TREZOR_BOARD +#ifdef KERNEL_MODE + 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}; @@ -214,17 +216,4 @@ void SystemInit(void) { 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(); -} +#endif // #ifdef KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/platform.h b/core/embed/trezorhal/stm32u5/platform.h index 6a84e773ea4..d5c9ffb6e51 100644 --- a/core/embed/trezorhal/stm32u5/platform.h +++ b/core/embed/trezorhal/stm32u5/platform.h @@ -34,8 +34,6 @@ typedef enum { } 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); @@ -44,16 +42,6 @@ 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/sdcard.c b/core/embed/trezorhal/stm32u5/sdcard.c index 1f8d22c57e0..4d83000ae15 100644 --- a/core/embed/trezorhal/stm32u5/sdcard.c +++ b/core/embed/trezorhal/stm32u5/sdcard.c @@ -49,13 +49,15 @@ #include #include "irq.h" +#include "mpu.h" #include "sdcard.h" -#include "supervise.h" #define SDMMC_CLK_ENABLE() __HAL_RCC_SDMMC1_CLK_ENABLE() #define SDMMC_CLK_DISABLE() __HAL_RCC_SDMMC1_CLK_DISABLE() #define SDMMC_IRQn SDMMC1_IRQn +#ifdef KERNEL_MODE + static SD_HandleTypeDef sd_handle = {0}; // this function is inspired by functions in stm32f4xx_ll_sdmmc.c @@ -138,8 +140,8 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { SDMMC_CLK_ENABLE(); // NVIC configuration for SDIO interrupts - svc_setpriority(SDMMC_IRQn, IRQ_PRI_SDIO); - svc_enableIRQ(SDMMC_IRQn); + NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(SDMMC_IRQn); } // GPIO have already been initialised by sdcard_init @@ -147,7 +149,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { if (hsd->Instance == sd_handle.Instance) { - svc_disableIRQ(SDMMC_IRQn); + NVIC_DisableIRQ(SDMMC_IRQn); SDMMC_CLK_DISABLE(); } } @@ -235,9 +237,11 @@ uint64_t sdcard_get_capacity_in_bytes(void) { void SDMMC1_IRQHandler(void) { IRQ_ENTER(SDIO_IRQn); + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); if (sd_handle.Instance) { HAL_SD_IRQHandler(&sd_handle); } + mpu_restore(mpu_mode); IRQ_EXIT(SDIO_IRQn); } @@ -257,13 +261,13 @@ static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t start = HAL_GetTick(); for (;;) { // Do an atomic check of the state; WFI will exit even if IRQs are disabled - uint32_t irq_state = disable_irq(); + irq_key_t irq_key = irq_lock(); if (sd->State != HAL_SD_STATE_BUSY) { - enable_irq(irq_state); + irq_unlock(irq_key); break; } __WFI(); - enable_irq(irq_state); + irq_unlock(irq_key); if (HAL_GetTick() - start >= timeout) { return HAL_TIMEOUT; } @@ -301,16 +305,12 @@ secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num, HAL_StatusTypeDef err = HAL_OK; - // we must disable USB irqs to prevent MSC contention with SD card - uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - sdcard_reset_periph(); err = HAL_SD_ReadBlocks_DMA(&sd_handle, (uint8_t *)dest, block_num, num_blocks); if (err == HAL_OK) { err = sdcard_wait_finished(&sd_handle, 5000); } - restore_irq_pri(basepri); return sectrue * (err == HAL_OK); } @@ -329,9 +329,6 @@ secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, HAL_StatusTypeDef err = HAL_OK; - // we must disable USB irqs to prevent MSC contention with SD card - uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - sdcard_reset_periph(); err = HAL_SD_WriteBlocks_DMA(&sd_handle, (uint8_t *)src, block_num, num_blocks); @@ -339,7 +336,7 @@ secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, err = sdcard_wait_finished(&sd_handle, 5000); } - restore_irq_pri(basepri); - return sectrue * (err == HAL_OK); } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/secret.c b/core/embed/trezorhal/stm32u5/secret.c index d148f0a54d7..f6b3a2d4f53 100644 --- a/core/embed/trezorhal/stm32u5/secret.c +++ b/core/embed/trezorhal/stm32u5/secret.c @@ -1,13 +1,18 @@ #include "secret.h" #include #include +#include "bootutils.h" #include "common.h" #include "flash.h" +#include "flash_utils.h" #include "memzero.h" #include "model.h" +#include "mpu.h" #include "rng.h" #include "secure_aes.h" +#ifdef KERNEL_MODE + static secbool bootloader_locked = secfalse; secbool secret_verify_header(void) { @@ -18,17 +23,21 @@ secbool secret_verify_header(void) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + bootloader_locked = memcmp(addr, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0 ? sectrue : secfalse; + + mpu_restore(mpu_mode); + return bootloader_locked; } secbool secret_ensure_initialized(void) { if (sectrue != secret_verify_header()) { - ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), - "erase storage failed"); + ensure(erase_storage(NULL), "erase storage failed"); secret_erase(); secret_write_header(); return secfalse; @@ -57,6 +66,7 @@ void secret_write_header(void) { } void secret_write(const uint8_t *data, uint32_t offset, uint32_t len) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); ensure(flash_unlock_write(), "secret write"); for (int i = 0; i < len / 16; i++) { ensure(flash_area_write_quadword(&SECRET_AREA, offset + (i * 16), @@ -64,6 +74,7 @@ void secret_write(const uint8_t *data, uint32_t offset, uint32_t len) { "secret write"); } ensure(flash_lock_write(), "secret write"); + mpu_restore(mpu_mode); } secbool secret_read(uint8_t *data, uint32_t offset, uint32_t len) { @@ -75,7 +86,10 @@ secbool secret_read(uint8_t *data, uint32_t offset, uint32_t len) { if (addr == NULL) { return secfalse; } + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); memcpy(data, addr, len); + mpu_restore(mpu_mode); return sectrue; } @@ -105,6 +119,8 @@ static secbool secret_present(uint32_t offset, uint32_t len) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + int secret_empty_bytes = 0; for (int i = 0; i < len; i++) { @@ -114,6 +130,9 @@ static secbool secret_present(uint32_t offset, uint32_t len) { secret_empty_bytes++; } } + + mpu_restore(mpu_mode); + return sectrue * (secret_empty_bytes != len); } @@ -122,8 +141,7 @@ static secbool secret_present(uint32_t offset, uint32_t len) { // read access to it. static void secret_bhk_load(void) { if (sectrue == secret_bhk_locked()) { - delete_secrets(); - NVIC_SystemReset(); + reboot(); } uint32_t secret[SECRET_BHK_LEN / sizeof(uint32_t)] = {0}; @@ -152,6 +170,8 @@ static void secret_bhk_load(void) { } void secret_bhk_regenerate(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + ensure(flash_area_erase(&BHK_AREA, NULL), "Failed regenerating BHK"); ensure(flash_unlock_write(), "Failed regenerating BHK"); for (int i = 0; i < 2; i++) { @@ -164,6 +184,9 @@ void secret_bhk_regenerate(void) { memzero(val, sizeof(val)); ensure(res, "Failed regenerating BHK"); } + + mpu_restore(mpu_mode); + ensure(flash_lock_write(), "Failed regenerating BHK"); } @@ -187,6 +210,8 @@ secbool secret_optiga_writable(void) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + int secret_empty_bytes = 0; for (int i = 0; i < len; i++) { @@ -196,6 +221,9 @@ secbool secret_optiga_writable(void) { secret_empty_bytes++; } } + + mpu_restore(mpu_mode); + return sectrue * (secret_empty_bytes == len); } @@ -224,7 +252,8 @@ static void secret_optiga_cache(void) { secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]) { uint8_t secret_enc[SECRET_OPTIGA_KEY_LEN] = {0}; if (sectrue != secure_aes_ecb_encrypt_hw(secret, sizeof(secret_enc), - secret_enc, SECURE_AES_KEY_DHUK)) { + secret_enc, + SECURE_AES_KEY_DHUK_SP)) { return secfalse; } secret_write(secret_enc, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); @@ -251,7 +280,7 @@ secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]) { } secbool res = secure_aes_ecb_decrypt_hw( - (uint8_t *)secret, SECRET_OPTIGA_KEY_LEN, dest, SECURE_AES_KEY_DHUK); + (uint8_t *)secret, SECRET_OPTIGA_KEY_LEN, dest, SECURE_AES_KEY_DHUK_SP); memzero(secret, sizeof(secret)); return res; @@ -272,7 +301,9 @@ void secret_optiga_erase(void) { } void secret_erase(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); + mpu_restore(mpu_mode); } void secret_prepare_fw(secbool allow_run_with_secret, secbool trust_all) { @@ -321,3 +352,5 @@ void secret_prepare_fw(secbool allow_run_with_secret, secbool trust_all) { secret_disable_access(); } } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/secure_aes.c b/core/embed/trezorhal/stm32u5/secure_aes.c index 61fa3cd8a0d..036c3958a38 100644 --- a/core/embed/trezorhal/stm32u5/secure_aes.c +++ b/core/embed/trezorhal/stm32u5/secure_aes.c @@ -17,31 +17,24 @@ * along with this program. If not, see . */ +#include #include #include STM32_HAL_H #include #include #include +#include "model.h" +#include "syscall.h" + #include "memzero.h" +#define SAES_DATA_SIZE_WITH_UPRIV_KEY 32 #define AES_BLOCK_SIZE 16 -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; +#ifdef KERNEL_MODE - // 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; -} +#include "irq.h" static void secure_aes_load_bhk(void) { TAMP->BKP0R; @@ -56,19 +49,159 @@ static void secure_aes_load_bhk(void) { static uint32_t get_keysel(secure_aes_keysel_t key) { switch (key) { - case SECURE_AES_KEY_DHUK: + case SECURE_AES_KEY_DHUK_SP: return CRYP_KEYSEL_HW; case SECURE_AES_KEY_BHK: return CRYP_KEYSEL_SW; - case SECURE_AES_KEY_XORK: + case SECURE_AES_KEY_XORK_SP: + case SECURE_AES_KEY_XORK_SN: return CRYP_KEYSEL_HSW; default: return 0; } } +static secbool is_key_supported(secure_aes_keysel_t key) { + switch (key) { + case SECURE_AES_KEY_DHUK_SP: + case SECURE_AES_KEY_BHK: + case SECURE_AES_KEY_XORK_SP: + return sectrue; + default: + return secfalse; + } +} + +#ifdef SYSCALL_DISPATCH + +__attribute__((section(".udata"))) +uint32_t saes_input[SAES_DATA_SIZE_WITH_UPRIV_KEY / sizeof(uint32_t)]; + +__attribute__((section(".udata"))) +uint32_t saes_output[SAES_DATA_SIZE_WITH_UPRIV_KEY / sizeof(uint32_t)]; + +__attribute__((section(".uflash"), used, naked, no_stack_protector)) uint32_t +saes_invoke(void) { + // reset the key loaded in SAES + MODIFY_REG(SAES->CR, AES_CR_KEYSEL, CRYP_KEYSEL_NORMAL); + + while (HAL_IS_BIT_SET(SAES->SR, CRYP_FLAG_BUSY)) { + } + while (HAL_IS_BIT_SET(SAES->ISR, CRYP_FLAG_RNGEIF)) { + } + + MODIFY_REG(SAES->CR, + AES_CR_KMOD | AES_CR_DATATYPE | AES_CR_KEYSIZE | AES_CR_CHMOD | + AES_CR_KEYSEL | AES_CR_KEYPROT, + CRYP_KEYMODE_NORMAL | CRYP_NO_SWAP | CRYP_KEYSIZE_256B | + CRYP_AES_ECB | CRYP_KEYSEL_HSW | CRYP_KEYPROT_DISABLE); + + TAMP->BKP0R; + TAMP->BKP1R; + TAMP->BKP2R; + TAMP->BKP3R; + TAMP->BKP4R; + TAMP->BKP5R; + TAMP->BKP6R; + TAMP->BKP7R; + +#define CRYP_OPERATINGMODE_ENCRYPT 0x00000000U /*!< Encryption mode(Mode 1) */ + + /* Set the operating mode and normal key selection */ + MODIFY_REG(SAES->CR, AES_CR_MODE | AES_CR_KMOD, + CRYP_OPERATINGMODE_ENCRYPT | CRYP_KEYMODE_NORMAL); + + SAES->CR |= AES_CR_EN; + + for (int j = 0; j < SAES_DATA_SIZE_WITH_UPRIV_KEY / AES_BLOCK_SIZE; j++) { + /* Write the input block in the IN FIFO */ + SAES->DINR = saes_input[j * 4 + 0]; + SAES->DINR = saes_input[j * 4 + 1]; + SAES->DINR = saes_input[j * 4 + 2]; + SAES->DINR = saes_input[j * 4 + 3]; + + while (HAL_IS_BIT_CLR(SAES->ISR, AES_ISR_CCF)) { + } + + /* Clear CCF Flag */ + SET_BIT(SAES->ICR, CRYP_CLEAR_CCF); + + /* Read the output block from the output FIFO */ + for (int i = 0U; i < 4U; i++) { + saes_output[j * 4 + i] = SAES->DOUTR; + } + } + + SAES->CR &= ~AES_CR_EN; + + // reset the key loaded in SAES + MODIFY_REG(SAES->CR, AES_CR_KEYSEL, CRYP_KEYSEL_NORMAL); + + syscall_return_from_callback(sectrue); + return 0; +} + +extern uint32_t sram_u_start; +extern uint32_t sram_u_end; + +secbool unpriv_encrypt(const uint8_t* input, size_t size, uint8_t* output, + secure_aes_keysel_t key) { + if (size != SAES_DATA_SIZE_WITH_UPRIV_KEY) { + return secfalse; + } + + if (key != SECURE_AES_KEY_XORK_SN) { + return secfalse; + } + + uint32_t prev_svc_prio = NVIC_GetPriority(SVCall_IRQn); + NVIC_SetPriority(SVCall_IRQn, IRQ_PRI_HIGHEST); + uint32_t basepri = __get_BASEPRI(); + __set_BASEPRI(IRQ_PRI_HIGHEST + 1); + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SAES); + + memset(&sram_u_start, 0, &sram_u_end - &sram_u_start); + memcpy(saes_input, input, size); + + SAES->CR |= AES_CR_KEYSEL_0; + + __HAL_RCC_SAES_CLK_DISABLE(); + __HAL_RCC_SAES_FORCE_RESET(); + __HAL_RCC_SAES_RELEASE_RESET(); + __HAL_RCC_SAES_CLK_ENABLE(); + + secbool retval = invoke_unpriv(saes_invoke); + + __HAL_RCC_SAES_CLK_DISABLE(); + __HAL_RCC_SAES_FORCE_RESET(); + __HAL_RCC_SAES_RELEASE_RESET(); + __HAL_RCC_SAES_CLK_ENABLE(); + + memcpy(output, saes_output, size); + memset(&sram_u_start, 0, &sram_u_end - &sram_u_start); + + mpu_reconfig(mpu_mode); + + __set_BASEPRI(basepri); + NVIC_SetPriority(SVCall_IRQn, prev_svc_prio); + + return retval; +} +#endif + secbool secure_aes_ecb_encrypt_hw(const uint8_t* input, size_t size, uint8_t* output, secure_aes_keysel_t key) { +#ifdef SYSCALL_DISPATCH + if (key == SECURE_AES_KEY_XORK_SN) { + return unpriv_encrypt(input, size, output, key); + } +#endif + + if (sectrue != is_key_supported(key)) { + return secfalse; + } + CRYP_HandleTypeDef hcryp = {0}; uint32_t iv[] = {0, 0, 0, 0}; @@ -136,6 +269,10 @@ secbool secure_aes_ecb_encrypt_hw(const uint8_t* input, size_t size, secbool secure_aes_ecb_decrypt_hw(const uint8_t* input, size_t size, uint8_t* output, secure_aes_keysel_t key) { + if (sectrue != is_key_supported(key)) { + return secfalse; + } + CRYP_HandleTypeDef hcryp = {0}; uint32_t iv[] = {0, 0, 0, 0}; @@ -199,3 +336,21 @@ secbool secure_aes_ecb_decrypt_hw(const uint8_t* input, size_t size, return sectrue; } + +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; +} + +#endif diff --git a/core/embed/trezorhal/stm32u5/startup_stage_0.s b/core/embed/trezorhal/stm32u5/startup_stage_0.s new file mode 100644 index 00000000000..e237fe57e9b --- /dev/null +++ b/core/embed/trezorhal/stm32u5/startup_stage_0.s @@ -0,0 +1,79 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // set the stack protection + ldr r0, =_sstack + add r0, r0, #128 // safety margin for the exception frame + msr MSPLIM, r0 + + bl SystemInit + + // read the first rng data and save it + ldr r0, =0 // r0 - previous value + ldr r1, =0 // r1 - whether to compare the previous value + bl rng_read + + // read the next rng data and make sure it is different than previous + // r0 - value returned from previous call + ldr r1, =1 // r1 - whether to compare the previous value + bl rng_read + mov r4, r0 // save TRNG output in r4 + + // wipe memory to remove any possible vestiges of confidential data + + +fill_ram: + + mov r2, r4 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_0_start + ldr r1, =_startup_clear_ram_0_end + bl memset_reg + ldr r0, =_startup_clear_ram_1_start + ldr r1, =_startup_clear_ram_1_end + bl memset_reg + ldr r0, =_startup_clear_ram_2_start + ldr r1, =_startup_clear_ram_2_end + 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, =_startup_clear_ram_0_start + ldr r1, =_startup_clear_ram_0_end + bl memset_reg + ldr r0, =_startup_clear_ram_1_start + ldr r1, =_startup_clear_ram_1_end + bl memset_reg + ldr r0, =_startup_clear_ram_2_start + ldr r1, =_startup_clear_ram_2_end + 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 confidential data in from flash + ldr r0, =confidential_vma // dst addr + ldr r1, =confidential_lma // src addr + ldr r2, =confidential_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/startup_stm32u5.s b/core/embed/trezorhal/stm32u5/startup_stage_1.s similarity index 60% rename from core/embed/bootloader/startup_stm32u5.s rename to core/embed/trezorhal/stm32u5/startup_stage_1.s index 0f90b010878..53ba794d391 100644 --- a/core/embed/bootloader/startup_stm32u5.s +++ b/core/embed/trezorhal/stm32u5/startup_stage_1.s @@ -7,34 +7,19 @@ reset_handler: // set the stack protection ldr r0, =_sstack - add r0, r0, #16 // padding + add r0, r0, #128 // safety margin for the exception frame msr MSPLIM, r0 // 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 + ldr r0, =_startup_clear_ram_0_start + ldr r1, =_startup_clear_ram_0_end 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 + ldr r0, =_startup_clear_ram_1_start + ldr r1, =_startup_clear_ram_1_end 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 + ldr r0, =_startup_clear_ram_2_start + ldr r1, =_startup_clear_ram_2_end bl memset_reg // copy data in from flash @@ -57,7 +42,7 @@ reset_handler: // copy & clear g_boot_command ldr r0, =g_boot_command ldr r1, [r0] - ldr r0, =g_boot_command_shadow + ldr r0, =g_boot_command_saved str r1, [r0] ldr r0, =g_boot_command mov r1, #0 diff --git a/core/embed/reflash/startup_stm32f4.s b/core/embed/trezorhal/stm32u5/startup_stage_2.s similarity index 60% rename from core/embed/reflash/startup_stm32f4.s rename to core/embed/trezorhal/stm32u5/startup_stage_2.s index ad8bc096ee3..7813166f8ce 100644 --- a/core/embed/reflash/startup_stm32f4.s +++ b/core/embed/trezorhal/stm32u5/startup_stage_2.s @@ -5,20 +5,21 @@ .global reset_handler .type reset_handler, STT_FUNC reset_handler: + // set the stack protection + ldr r0, =_sstack + add r0, r0, #128 // safety margin for the exception frame + msr MSPLIM, r0 + // setup environment for subsequent stage of code - ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM - ldr r2, =0 // r2 - the word-sized value to be written + ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_0_start + ldr r1, =_startup_clear_ram_0_end 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 - ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_1_start + ldr r1, =_startup_clear_ram_1_end bl memset_reg - - ldr r0, =sram_start // r0 - point to beginning of SRAM - ldr r1, =sram_end // r1 - point to byte after the end of SRAM - ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =_startup_clear_ram_2_start + ldr r1, =_startup_clear_ram_2_end bl memset_reg // copy data in from flash @@ -27,6 +28,12 @@ reset_handler: ldr r2, =data_size // size in bytes bl memcpy + // copy confidential data in from flash + ldr r0, =confidential_vma // dst addr + ldr r1, =confidential_lma // src addr + ldr r2, =confidential_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 diff --git a/core/embed/trezorhal/stm32u5/startup_stage_4.s b/core/embed/trezorhal/stm32u5/startup_stage_4.s new file mode 100644 index 00000000000..cc26b7470b8 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/startup_stage_4.s @@ -0,0 +1,43 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + + push {r0, r1} + + // setup the stack protector with provided random value + ldr r0, = __stack_chk_guard + str r2, [r0] + + ldr r0, =bss_start + ldr r1, =0 + ldr r2, =bss_end + sub r2, r2, r0 + bl memset + + // copy data in from flash + ldr r0, =data_vma + ldr r1, =data_lma + ldr r2, =data_size + bl memcpy + + // copy confidential data in from flash + ldr r0, =confidential_vma + ldr r1, =confidential_lma + ldr r2, =confidential_size + bl memcpy + + pop {r0, r1} + + // enter the application code + // returns exit code in r0 + bl main + + // terminate the application + // pass exit code in r0 + b system_exit + + .end diff --git a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h index 203b2245c25..e5b411bd0f5 100644 --- a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h +++ b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h @@ -192,9 +192,8 @@ extern "C" { * @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 VDD_VALUE 3300UL /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY 0UL /*!< tick interrupt priority */ #define USE_RTOS 0U #define PREFETCH_ENABLE 1U /*!< Enable prefetch */ @@ -554,7 +553,8 @@ extern "C" { */ #define assert_param(expr) \ ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) -/* Exported functions ------------------------------------------------------- */ +/* Exported functions + ------------------------------------------------------- */ void assert_failed(uint8_t *file, uint32_t line); #else #define assert_param(expr) ((void)0U) diff --git a/core/embed/trezorhal/stm32u5/supervise.c b/core/embed/trezorhal/stm32u5/supervise.c deleted file mode 120000 index 385e9d43cad..00000000000 --- a/core/embed/trezorhal/stm32u5/supervise.c +++ /dev/null @@ -1 +0,0 @@ -../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 deleted file mode 120000 index f519770f494..00000000000 --- a/core/embed/trezorhal/stm32u5/supervise.h +++ /dev/null @@ -1 +0,0 @@ -../stm32f4/supervise.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/syscall.c b/core/embed/trezorhal/stm32u5/syscall.c new file mode 120000 index 00000000000..4995488e2a7 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/syscall.c @@ -0,0 +1 @@ +../stm32f4/syscall.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/syscall.h b/core/embed/trezorhal/stm32u5/syscall.h new file mode 120000 index 00000000000..8563747ddfd --- /dev/null +++ b/core/embed/trezorhal/stm32u5/syscall.h @@ -0,0 +1 @@ +../stm32f4/syscall.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/syscall_dispatch.c b/core/embed/trezorhal/stm32u5/syscall_dispatch.c new file mode 120000 index 00000000000..f7542fb99e5 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/syscall_dispatch.c @@ -0,0 +1 @@ +../stm32f4/syscall_dispatch.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/syscall_numbers.h b/core/embed/trezorhal/stm32u5/syscall_numbers.h new file mode 120000 index 00000000000..f2e572e9647 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/syscall_numbers.h @@ -0,0 +1 @@ +../stm32f4/syscall_numbers.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/syscall_stubs.c b/core/embed/trezorhal/stm32u5/syscall_stubs.c new file mode 120000 index 00000000000..877f2904f02 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/syscall_stubs.c @@ -0,0 +1 @@ +../stm32f4/syscall_stubs.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/systask.c b/core/embed/trezorhal/stm32u5/systask.c new file mode 120000 index 00000000000..7b6c139ae39 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/systask.c @@ -0,0 +1 @@ +../stm32f4/systask.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/system.c b/core/embed/trezorhal/stm32u5/system.c new file mode 120000 index 00000000000..36a84d685ca --- /dev/null +++ b/core/embed/trezorhal/stm32u5/system.c @@ -0,0 +1 @@ +../stm32f4/system.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/systick.h b/core/embed/trezorhal/stm32u5/systick.h deleted file mode 120000 index 1d1261d2cb5..00000000000 --- a/core/embed/trezorhal/stm32u5/systick.h +++ /dev/null @@ -1 +0,0 @@ -../stm32f4/systick.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/systick_internal.h b/core/embed/trezorhal/stm32u5/systick_internal.h new file mode 120000 index 00000000000..20607328674 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/systick_internal.h @@ -0,0 +1 @@ +../stm32f4/systick_internal.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/systimer.c b/core/embed/trezorhal/stm32u5/systimer.c new file mode 120000 index 00000000000..035d4ff20fd --- /dev/null +++ b/core/embed/trezorhal/stm32u5/systimer.c @@ -0,0 +1 @@ +../stm32f4/systimer.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/tamper.c b/core/embed/trezorhal/stm32u5/tamper.c index 6b74a54f483..4f6cfb605df 100644 --- a/core/embed/trezorhal/stm32u5/tamper.c +++ b/core/embed/trezorhal/stm32u5/tamper.c @@ -17,11 +17,14 @@ * along with this program. If not, see . */ +#include #include -#include +#include #include #include STM32_HAL_H +#ifdef KERNEL_MODE + // Fixes a typo in CMSIS Device library for STM32U5 #undef TAMP_CR3_ITAMP7NOER_Msk #undef TAMP_CR3_ITAMP7NOER @@ -227,13 +230,15 @@ void tamper_init(void) { TAMP_IER_ITAMP11IE | TAMP_IER_ITAMP12IE | TAMP_IER_ITAMP13IE; // Enable TAMP interrupt at NVIC controller - NVIC_SetPriority(TAMP_IRQn, IRQ_PRI_TAMP); + NVIC_SetPriority(TAMP_IRQn, IRQ_PRI_HIGHEST); NVIC_EnableIRQ(TAMP_IRQn); } // Interrupt handle for all tamper events // It displays an error message void TAMP_IRQHandler(void) { + mpu_reconfig(MPU_MODE_DEFAULT); + uint32_t sr = TAMP->SR; TAMP->SCR = sr; @@ -271,3 +276,5 @@ void TAMP_IRQHandler(void) { error_shutdown_ex("INTERNAL TAMPER", reason, NULL); #endif } + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/touch/sitronix.c b/core/embed/trezorhal/stm32u5/touch/sitronix.c index b3f2c70e145..eb4d127cfca 100644 --- a/core/embed/trezorhal/stm32u5/touch/sitronix.c +++ b/core/embed/trezorhal/stm32u5/touch/sitronix.c @@ -1,7 +1,11 @@ #include STM32_HAL_H #include TREZOR_BOARD -#include "i2c.h" +#ifdef KERNEL_MODE + +#include "common.h" +#include "i2c_bus.h" +#include "irq.h" /** @addtogroup STM32U5x9J_DISCOVERY * @{ @@ -48,7 +52,12 @@ #define BSP_ERROR_BUS_DMA_FAILURE -107 /* TS I2C address */ -#define TS_I2C_ADDRESS 0xE0U +#define TS_I2C_ADDRESS 0x70U + +#define SITRONIX_OK (0) +#define SITRONIX_ERROR (-1) + +static i2c_bus_t *i2c_bus = NULL; /******************************************************************************* * Function Name : sitronix_read_reg @@ -58,8 +67,29 @@ * Output : pdata Read *******************************************************************************/ int32_t sitronix_read_reg(uint8_t reg, uint8_t *pdata, uint16_t length) { - return i2c_mem_read(TOUCH_I2C_INSTANCE, TS_I2C_ADDRESS, reg, length, pdata, - length, 1000); + i2c_op_t ops[] = { + { + .flags = I2C_FLAG_TX | I2C_FLAG_EMBED, + .size = 1, + .data = {reg}, + }, + { + .flags = I2C_FLAG_RX, + .size = length, + .ptr = pdata, + }, + }; + + i2c_packet_t pkt = { + .address = TS_I2C_ADDRESS, + .timeout = 100, + .op_count = ARRAY_LENGTH(ops), + .ops = ops, + }; + + i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &pkt); + + return (status == I2C_STATUS_OK) ? SITRONIX_OK : SITRONIX_ERROR; } /******************************************************************************* @@ -70,8 +100,29 @@ int32_t sitronix_read_reg(uint8_t reg, uint8_t *pdata, uint16_t length) { * Output : None *******************************************************************************/ int32_t sitronix_write_reg(uint8_t reg, uint8_t *pdata, uint16_t length) { - return i2c_mem_write(TOUCH_I2C_INSTANCE, TS_I2C_ADDRESS, reg, length, pdata, - length, 1000); + i2c_op_t ops[] = { + { + .flags = I2C_FLAG_TX | I2C_FLAG_EMBED, + .size = 1, + .data = {reg}, + }, + { + .flags = I2C_FLAG_TX, + .size = length, + .ptr = pdata, + }, + }; + + i2c_packet_t pkt = { + .address = TS_I2C_ADDRESS, + .timeout = 100, + .op_count = ARRAY_LENGTH(ops), + .ops = ops, + }; + + i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &pkt); + + return (status == I2C_STATUS_OK) ? SITRONIX_OK : SITRONIX_ERROR; } /******************************************************************************* @@ -82,7 +133,24 @@ int32_t sitronix_write_reg(uint8_t reg, uint8_t *pdata, uint16_t length) { * Output : pdata Read *******************************************************************************/ int32_t sitronix_read_data(uint8_t *pdata, uint16_t length) { - return i2c_receive(TOUCH_I2C_INSTANCE, TS_I2C_ADDRESS, pdata, length, 1000); + i2c_op_t ops[] = { + { + .flags = I2C_FLAG_RX, + .size = length, + .ptr = pdata, + }, + }; + + i2c_packet_t pkt = { + .address = TS_I2C_ADDRESS, + .timeout = 100, + .op_count = ARRAY_LENGTH(ops), + .ops = ops, + }; + + i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &pkt); + + return (status == I2C_STATUS_OK) ? SITRONIX_OK : SITRONIX_ERROR; } /* Includes ------------------------------------------------------------------*/ @@ -95,8 +163,6 @@ int32_t sitronix_read_data(uint8_t *pdata, uint16_t length) { /** @defgroup SITRONIX_Exported_Constants SITRONIX Exported Constants * @{ */ -#define SITRONIX_OK (0) -#define SITRONIX_ERROR (-1) /* Max detectable simultaneous touches */ #define SITRONIX_MAX_DETECTABLE_TOUCH 10U @@ -746,6 +812,11 @@ static int32_t SITRONIX_Probe(uint32_t Instance); int32_t BSP_TS_Init(uint32_t Instance, TS_Init_t *TS_Init) { int32_t status = BSP_ERROR_NONE; + i2c_bus = i2c_bus_open(TOUCH_I2C_INSTANCE); + if (i2c_bus == NULL) { + return BSP_ERROR_COMPONENT_FAILURE; + } + if ((TS_Init == NULL) || (Instance >= TS_INSTANCES_NBR)) { status = BSP_ERROR_WRONG_PARAM; } else { @@ -797,6 +868,11 @@ int32_t BSP_TS_DeInit(uint32_t Instance) { if (Ts_Drv[Instance]->DeInit(Ts_CompObj[Instance]) < 0) { status = BSP_ERROR_COMPONENT_FAILURE; } + + if (i2c_bus != NULL) { + i2c_bus_close(i2c_bus); + i2c_bus = NULL; + } } return status; @@ -823,8 +899,8 @@ int32_t BSP_TS_EnableIT(uint32_t Instance) { HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure); /* Enable and set Touch screen EXTI Interrupt to the lowest priority */ - HAL_NVIC_SetPriority((IRQn_Type)(TS_INT_EXTI_IRQn), 0x0F, 0x00); - HAL_NVIC_EnableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn)); + NVIC_SetPriority((IRQn_Type)(TS_INT_EXTI_IRQn), IRQ_PRI_NORMAL); + NVIC_EnableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn)); return BSP_ERROR_NONE; } @@ -1240,3 +1316,5 @@ uint32_t touch_get_event(void) { return event; } + +#endif diff --git a/core/embed/trezorhal/stm32u5/trustzone.c b/core/embed/trezorhal/stm32u5/trustzone.c index f77fbb4a159..047b06e880f 100644 --- a/core/embed/trezorhal/stm32u5/trustzone.c +++ b/core/embed/trezorhal/stm32u5/trustzone.c @@ -20,6 +20,7 @@ #include #include STM32_HAL_H +#include "irq.h" #ifdef BOARDLOADER @@ -142,8 +143,8 @@ void trustzone_init_boardloader(void) { 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); + NVIC_SetPriority(GTZC_IRQn, IRQ_PRI_HIGHEST); + NVIC_EnableIRQ(GTZC_IRQn); } #endif // BOARDLOADER diff --git a/core/embed/trezorhal/stm32u5/util.s b/core/embed/trezorhal/stm32u5/util.S similarity index 63% rename from core/embed/trezorhal/stm32u5/util.s rename to core/embed/trezorhal/stm32u5/util.S index 827451624a6..65fe4f94d0b 100644 --- a/core/embed/trezorhal/stm32u5/util.s +++ b/core/embed/trezorhal/stm32u5/util.S @@ -2,6 +2,8 @@ .text +#ifdef KERNEL_MODE + .global memset_reg .type memset_reg, STT_FUNC memset_reg: @@ -35,26 +37,14 @@ jump_to: 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 + ldr r0, =_handoff_clear_ram_0_start + ldr r1, =_handoff_clear_ram_0_end bl memset_reg - ldr r0, =sram3_start // r0 - point to beginning of SRAM - ldr r1, =__fb_start // r1 - point to beginning of framebuffer + ldr r0, =_handoff_clear_ram_1_start + ldr r1, =_handoff_clear_ram_1_end 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 + ldr r0, =_handoff_clear_ram_2_start + ldr r1, =_handoff_clear_ram_2_end bl memset_reg mov lr, r4 @@ -107,26 +97,17 @@ shutdown_privileged: 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 + ldr r0, =_shutdown_clear_ram_0_start + ldr r1, =_shutdown_clear_ram_0_end 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 + ldr r0, =_shutdown_clear_ram_1_start + ldr r1, =_shutdown_clear_ram_1_end 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 + ldr r0, =_shutdown_clear_ram_2_start + ldr r1, =_shutdown_clear_ram_2_end 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 + ldr r0, =_shutdown_clear_ram_3_start + ldr r1, =_shutdown_clear_ram_3_end bl memset_reg ldr r0, =1 @@ -134,4 +115,6 @@ shutdown_privileged: ldr r0, =0 b . // loop forever +#endif + .end diff --git a/core/embed/trezorhal/stm32u5/vectortable.s b/core/embed/trezorhal/stm32u5/vectortable.S similarity index 97% rename from core/embed/trezorhal/stm32u5/vectortable.s rename to core/embed/trezorhal/stm32u5/vectortable.S index 2a9e9cb6530..d4f79d19503 100644 --- a/core/embed/trezorhal/stm32u5/vectortable.s +++ b/core/embed/trezorhal/stm32u5/vectortable.S @@ -2,6 +2,8 @@ .text +#ifdef KERNEL_MODE + .global default_handler .type default_handler, STT_FUNC default_handler: @@ -174,4 +176,14 @@ vector_table: add_handler DSI_IRQHandler add_handler DCACHE2_IRQHandler +#else + + .section .vector_table, "a" +vector_table: + .word _sstack + .word _stack_size + .word reset_handler + +#endif + .end diff --git a/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_driver.c b/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_driver.c index daa321df20d..714f6ae30f8 100644 --- a/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_driver.c +++ b/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_driver.c @@ -30,60 +30,96 @@ #error "Incompatible display resolution" #endif -// Display driver context. -typedef struct { - // Current display orientation (0, 90, 180, 270) - int orientation_angle; - // Current backlight level ranging from 0 to 255 - int backlight_level; -} display_driver_t; +#ifdef KERNEL_MODE // Display driver instance -static display_driver_t g_display_driver; - -void display_init(void) { - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; - - // Initializes the common periph clock - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LTDC | RCC_PERIPHCLK_DSI; - PeriphClkInit.DsiClockSelection = RCC_DSICLKSOURCE_PLL3; - PeriphClkInit.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3; - PeriphClkInit.PLL3.PLL3Source = RCC_PLLSOURCE_HSE; - PeriphClkInit.PLL3.PLL3M = 4; - PeriphClkInit.PLL3.PLL3N = 125; - PeriphClkInit.PLL3.PLL3P = 8; - PeriphClkInit.PLL3.PLL3Q = 2; - PeriphClkInit.PLL3.PLL3R = 24; - PeriphClkInit.PLL3.PLL3RGE = RCC_PLLVCIRANGE_0; - PeriphClkInit.PLL3.PLL3FRACN = 0; - PeriphClkInit.PLL3.PLL3ClockOut = RCC_PLL3_DIVP | RCC_PLL3_DIVR; - HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); - - // Clear framebuffers - memset(physical_frame_buffer_0, 0x00, PHYSICAL_FRAME_BUFFER_SIZE); - memset(physical_frame_buffer_1, 0x00, PHYSICAL_FRAME_BUFFER_SIZE); - - BSP_LCD_Init(0, LCD_ORIENTATION_PORTRAIT); - BSP_LCD_SetBrightness(0, 100); - BSP_LCD_DisplayOn(0); -} +display_driver_t g_display_driver = { + .initialized = false, +}; + +void display_init(display_content_mode_t mode) { + display_driver_t *drv = &g_display_driver; + + if (drv->initialized) { + return; + } -void display_reinit(void) { - BSP_LCD_Reinit(0); - if (current_frame_buffer == 0) { - BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S); + if (mode == DISPLAY_RESET_CONTENT) { + __HAL_RCC_DSI_FORCE_RESET(); + __HAL_RCC_LTDC_FORCE_RESET(); + __HAL_RCC_GFXMMU_FORCE_RESET(); + __HAL_RCC_DSI_RELEASE_RESET(); + __HAL_RCC_LTDC_RELEASE_RESET(); + __HAL_RCC_GFXMMU_RELEASE_RESET(); + + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + + // Initializes the common periph clock + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LTDC | RCC_PERIPHCLK_DSI; + PeriphClkInit.DsiClockSelection = RCC_DSICLKSOURCE_PLL3; + PeriphClkInit.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3; + PeriphClkInit.PLL3.PLL3Source = RCC_PLLSOURCE_HSE; + PeriphClkInit.PLL3.PLL3M = 4; + PeriphClkInit.PLL3.PLL3N = 125; + PeriphClkInit.PLL3.PLL3P = 8; + PeriphClkInit.PLL3.PLL3Q = 2; + PeriphClkInit.PLL3.PLL3R = 24; + PeriphClkInit.PLL3.PLL3RGE = RCC_PLLVCIRANGE_0; + PeriphClkInit.PLL3.PLL3FRACN = 0; + PeriphClkInit.PLL3.PLL3ClockOut = RCC_PLL3_DIVP | RCC_PLL3_DIVR; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); + + // Clear framebuffers + memset(physical_frame_buffer_0, 0x00, PHYSICAL_FRAME_BUFFER_SIZE); + memset(physical_frame_buffer_1, 0x00, PHYSICAL_FRAME_BUFFER_SIZE); + + BSP_LCD_Init(0, LCD_ORIENTATION_PORTRAIT); + BSP_LCD_SetBrightness(0, 100); + BSP_LCD_DisplayOn(0); } else { - BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S); + // Retain display content + BSP_LCD_Reinit(0); + if (current_frame_buffer == 0) { + BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S); + } else { + BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S); + } } + + drv->initialized = true; } -void display_finish_actions(void) { - // Not used and intentionally left empty +void display_deinit(display_content_mode_t mode) { + display_driver_t *drv = &g_display_driver; + + if (!drv->initialized) { + if (mode == DISPLAY_RESET_CONTENT) { + __HAL_RCC_DSI_FORCE_RESET(); + __HAL_RCC_LTDC_FORCE_RESET(); + __HAL_RCC_GFXMMU_FORCE_RESET(); + __HAL_RCC_DSI_RELEASE_RESET(); + __HAL_RCC_LTDC_RELEASE_RESET(); + __HAL_RCC_GFXMMU_RELEASE_RESET(); + } + return; + } + + if (mode == DISPLAY_RESET_CONTENT) { + BSP_LCD_DisplayOff(0); + BSP_LCD_SetBrightness(0, 0); + BSP_LCD_DeInit(0); + } + + drv->initialized = false; } int display_set_backlight(int level) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + // Just emulation, not doing anything drv->backlight_level = level; return level; @@ -92,12 +128,20 @@ int display_set_backlight(int level) { int display_get_backlight(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + return drv->orientation_angle; } int display_set_orientation(int angle) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + if (angle == 0 || angle == 90 || angle == 180 || angle == 270) { // Just emulation, not doing anything drv->orientation_angle = angle; @@ -109,14 +153,20 @@ int display_set_orientation(int angle) { int display_get_orientation(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + return drv->orientation_angle; } -void display_set_compatible_settings() {} - void display_fill(const gfx_bitblt_t *bb) { display_fb_info_t fb = display_get_frame_buffer(); + if (fb.ptr == NULL) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; @@ -127,6 +177,10 @@ void display_fill(const gfx_bitblt_t *bb) { void display_copy_rgb565(const gfx_bitblt_t *bb) { display_fb_info_t fb = display_get_frame_buffer(); + if (fb.ptr == NULL) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; @@ -137,6 +191,10 @@ void display_copy_rgb565(const gfx_bitblt_t *bb) { void display_copy_mono1p(const gfx_bitblt_t *bb) { display_fb_info_t fb = display_get_frame_buffer(); + if (fb.ptr == NULL) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; @@ -147,9 +205,15 @@ void display_copy_mono1p(const gfx_bitblt_t *bb) { void display_copy_mono4(const gfx_bitblt_t *bb) { display_fb_info_t fb = display_get_frame_buffer(); + if (fb.ptr == NULL) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; gfx_rgba8888_copy_mono4(&bb_new); } + +#endif diff --git a/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_fb.c b/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_fb.c index 5b425176cc8..7d96ea80a6f 100644 --- a/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_fb.c +++ b/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_fb.c @@ -26,6 +26,8 @@ #include #include "display_internal.h" +#ifdef KERNEL_MODE + // Physical frame buffers in internal SRAM memory __attribute__((section(".fb1"))) ALIGN_32BYTES(uint32_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]); @@ -39,6 +41,16 @@ __attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer = 0; display_fb_info_t display_get_frame_buffer(void) { + display_driver_t *drv = &g_display_driver; + + if (!drv->initialized) { + display_fb_info_t fb = { + .ptr = NULL, + .stride = 0, + }; + return fb; + } + uintptr_t addr; if (current_frame_buffer == 0) { @@ -63,6 +75,12 @@ display_fb_info_t display_get_frame_buffer(void) { } void display_refresh(void) { + display_driver_t *drv = &g_display_driver; + + if (!drv->initialized) { + return; + } + if (current_frame_buffer == 0) { current_frame_buffer = 1; BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S); @@ -75,3 +93,5 @@ void display_refresh(void) { sizeof(physical_frame_buffer_1)); } } + +#endif diff --git a/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_gfxmmu_lut.h b/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_gfxmmu_lut.h index 86528b9d9a4..ac502356d4c 100644 --- a/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_gfxmmu_lut.h +++ b/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_gfxmmu_lut.h @@ -29,7 +29,7 @@ extern "C" { #define GFXMMU_LUT_LAST 479 #define GFXMMU_LUT_SIZE 480 -uint32_t gfxmmu_lut[2 * GFXMMU_LUT_SIZE] = { +static const uint32_t gfxmmu_lut_config[2 * GFXMMU_LUT_SIZE] = { 0x00413601, // GFXMMU_LUT0L 0x003FFCA0, // GFXMMU_LUT0H 0x00433401, // GFXMMU_LUT1L diff --git a/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_internal.h b/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_internal.h index cf3a1e8b669..bb7d5582a23 100644 --- a/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_internal.h +++ b/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_internal.h @@ -20,8 +20,22 @@ #ifndef TREZOR_HAL_DISPLAY_INTERNAL_H #define TREZOR_HAL_DISPLAY_INTERNAL_H +#include #include +// Display driver context. +typedef struct { + // Set if the driver is initialized + bool initialized; + // Current display orientation (0, 90, 180, 270) + int orientation_angle; + // Current backlight level ranging from 0 to 255 + int backlight_level; +} display_driver_t; + +// Display driver instance +extern display_driver_t g_display_driver; + // Size of the physical frame buffer in bytes // // It's smaller than size of the virtual frame buffer @@ -50,9 +64,11 @@ extern uint32_t current_frame_buffer; #define LCD_ORIENTATION_LANDSCAPE_ROT180 3U int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation); +int32_t BSP_LCD_DeInit(uint32_t Instance); int32_t BSP_LCD_Reinit(uint32_t Instance); int32_t BSP_LCD_SetBrightness(uint32_t Instance, uint32_t Brightness); int32_t BSP_LCD_DisplayOn(uint32_t Instance); +int32_t BSP_LCD_DisplayOff(uint32_t Instance); int32_t BSP_LCD_SetFrameBuffer(uint32_t Instance, uint32_t fb_addr); #endif // TREZOR_HAL_DISPLAY_INTERNAL_H diff --git a/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_ltdc_dsi.c b/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_ltdc_dsi.c index fb3e1163221..e2964798134 100644 --- a/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_ltdc_dsi.c +++ b/core/embed/trezorhal/stm32u5/xdisplay/stm32u5a9j-dk/display_ltdc_dsi.c @@ -66,6 +66,9 @@ #include STM32_HAL_H #include "display_internal.h" +#include "irq.h" + +#ifdef KERNEL_MODE /* Common Error codes */ #define BSP_ERROR_NONE 0 @@ -86,15 +89,6 @@ #define BSP_BUTTON_USER_IT_PRIORITY \ 0x0FUL /* Default is lowest priority level */ -/* LCD interrupt priorities */ -#define BSP_LCD_GFXMMU_IT_PRIORITY \ - 0x0FUL /* Default is lowest priority level \ - */ -#define BSP_LCD_LTDC_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ -#define BSP_LCD_DSI_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ - -/* HSPI RAM interrupt priority */ -#define BSP_HSPI_RAM_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ #define LCD_PIXEL_FORMAT_ARGB8888 \ 0x00000000U /*!< ARGB8888 LTDC pixel format \ */ @@ -174,6 +168,9 @@ LTDC_HandleTypeDef hlcd_ltdc = {0}; DSI_HandleTypeDef hlcd_dsi = {0}; static DSI_VidCfgTypeDef DSIVidCfg = {0}; +__attribute__((section(".gfxmmu_table"))) +uint32_t gfxmmu_lut[2 * GFXMMU_LUT_SIZE]; + /** * @} */ @@ -210,6 +207,12 @@ static void DSI_EndOfRefreshCallback(DSI_HandleTypeDef *hdsi); * @retval BSP status. */ int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation) { + memset(&hlcd_gfxmmu, 0, sizeof(hlcd_gfxmmu)); + memset(&hlcd_ltdc, 0, sizeof(hlcd_ltdc)); + memset(&hlcd_dsi, 0, sizeof(hlcd_dsi)); + memset(&DSIVidCfg, 0, sizeof(DSIVidCfg)); + memcpy(gfxmmu_lut, gfxmmu_lut_config, sizeof(gfxmmu_lut)); + int32_t status = BSP_ERROR_NONE; if ((Instance >= LCD_INSTANCES_NBR) || @@ -1336,8 +1339,8 @@ static void GFXMMU_MspInit(GFXMMU_HandleTypeDef *hgfxmmu) { __HAL_RCC_GFXMMU_CLK_ENABLE(); /* Enable GFXMMU interrupt */ - HAL_NVIC_SetPriority(GFXMMU_IRQn, BSP_LCD_GFXMMU_IT_PRIORITY, 0); - HAL_NVIC_EnableIRQ(GFXMMU_IRQn); + NVIC_SetPriority(GFXMMU_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(GFXMMU_IRQn); } /** @@ -1350,7 +1353,7 @@ static void GFXMMU_MspDeInit(GFXMMU_HandleTypeDef *hgfxmmu) { UNUSED(hgfxmmu); /* Disable GFXMMU interrupt */ - HAL_NVIC_DisableIRQ(GFXMMU_IRQn); + NVIC_DisableIRQ(GFXMMU_IRQn); /* GFXMMU clock disable */ __HAL_RCC_GFXMMU_CLK_DISABLE(); @@ -1369,11 +1372,11 @@ static void LTDC_MspInit(LTDC_HandleTypeDef *hltdc) { __HAL_RCC_LTDC_CLK_ENABLE(); /* Enable LTDC interrupt */ - HAL_NVIC_SetPriority(LTDC_IRQn, BSP_LCD_LTDC_IT_PRIORITY, 0); - HAL_NVIC_EnableIRQ(LTDC_IRQn); + NVIC_SetPriority(LTDC_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(LTDC_IRQn); - HAL_NVIC_SetPriority(LTDC_ER_IRQn, BSP_LCD_LTDC_IT_PRIORITY, 0); - HAL_NVIC_EnableIRQ(LTDC_ER_IRQn); + NVIC_SetPriority(LTDC_ER_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(LTDC_ER_IRQn); } /** @@ -1386,8 +1389,8 @@ static void LTDC_MspDeInit(LTDC_HandleTypeDef *hltdc) { UNUSED(hltdc); /* Disable LTDC interrupts */ - HAL_NVIC_DisableIRQ(LTDC_ER_IRQn); - HAL_NVIC_DisableIRQ(LTDC_IRQn); + NVIC_DisableIRQ(LTDC_ER_IRQn); + NVIC_DisableIRQ(LTDC_IRQn); /* LTDC clock disable */ __HAL_RCC_LTDC_CLK_DISABLE(); @@ -1494,8 +1497,8 @@ static void DSI_MspInit(DSI_HandleTypeDef *hdsi) { /* Enable DSI NVIC interrupt */ /* Default is lowest priority level */ - HAL_NVIC_SetPriority(DSI_IRQn, 0x0FUL, 0); - HAL_NVIC_EnableIRQ(DSI_IRQn); + NVIC_SetPriority(DSI_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(DSI_IRQn); } /** @@ -1530,7 +1533,7 @@ static void DSI_MspDeInit(DSI_HandleTypeDef *hdsi) { __HAL_RCC_DSI_RELEASE_RESET(); /* Disable DSI interrupts */ - HAL_NVIC_DisableIRQ(DSI_IRQn); + NVIC_DisableIRQ(DSI_IRQn); } int32_t BSP_LCD_SetFrameBuffer(uint32_t Instance, uint32_t fb_addr) { @@ -1560,3 +1563,5 @@ int32_t BSP_LCD_Reinit(uint32_t Instance) { return status; } + +#endif diff --git a/core/embed/trezorhal/systask.h b/core/embed/trezorhal/systask.h new file mode 100644 index 00000000000..90170fdaf1c --- /dev/null +++ b/core/embed/trezorhal/systask.h @@ -0,0 +1,182 @@ +/* + * 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_SYSTASK_H +#define TREZORHAL_SYSTASK_H + +#include +#include +#include + +#include "mpu.h" + +// Termination reason for the task +typedef enum { + TASK_TERM_REASON_EXIT = 0, + TASK_TERM_REASON_ERROR, + TASK_TERM_REASON_FATAL, + TASK_TERM_REASON_FAULT, + +} systask_term_reason_t; + +typedef struct { + // Fault/exception number (-15..-1) + int irqn; + // Configurable Fault Status Register + // (combined UFSR/BFSR/MMFSR) + uint32_t cfsr; + // Hard Fault Status Register + uint32_t hfsr; + // Address associated with MemManage fault + uint32_t mmfar; + // Address associated with the BusFault + uint32_t bfar; + // Stack pointer at the time of the fault + // (MSP or PSP depending on the privilege level) + uint32_t sp; +#if !(defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)) + // Stack pointer limit (for the stack overflow detection) + uint32_t sp_lim; +#endif + +} system_fault_t; + +// Task post-mortem information +typedef struct { + // Reason for the task termination + systask_term_reason_t reason; + // Whether the error occurred in privileged mode + bool privileged; + + union { + // Argument passed to `systask_exit()` + struct { + int code; + } exit; + + // Fault information catched in `systask_exit_fault()` + system_fault_t fault; + + // Arguments passed to `systask_exit_fatal()` + struct { + uint32_t line; + char file[64]; + char expr[64]; + } fatal; + + // Arguments passed to `systask_exit_error()` + struct { + char title[64]; + char message[64]; + char footer[64]; + } error; + }; + +} systask_postmortem_t; + +// Error handler callback invoke when kernel task terminates. +// +// The purpose of this callbacks display RSOD (Red Screen of Death). +// +// The callback may be called from any context, including interrupt context. +typedef void (*systask_error_handler_t)(const systask_postmortem_t* pminfo); + +#ifdef KERNEL_MODE + +// Task context used by the kernel to save the state of each task +// when switching between them +typedef struct { + // `sp`, `sp_lim`, `exc_return` and `killed` should at the beginning + // and in this order to be compatible with the PendSV_Handler + // Stack pointer value + uint32_t sp; + // Stack pointer limit (ARMv8-M only) + uint32_t sp_lim; + // Exception return value + uint32_t exc_return; + // Set to nonzero, if the task is killed + uint32_t killed; + + // MPU mode the task is running in + mpu_mode_t mpu_mode; + // Task post-mortem information + systask_postmortem_t pminfo; + +} systask_t; + +// Initializes the scheduler for tasks +// +// No other task functions should be called before this function +void systask_scheduler_init(systask_error_handler_t error_handler); + +// Returns the currently running task +systask_t* systask_active(void); + +// Makes the given task the currently running task +void systask_yield_to(systask_t* task); + +// Initializes a task with the given stack pointer, stack size +// +// The task must be not be running when the function is called +void systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size); + +// Pushes data onto the stack of the task +// +// The task must be not be running when the function is called +uint32_t* systask_push_data(systask_t* task, const void* data, size_t size); + +// Pops data from the stack of the task +// +// The task must be not be running when the function is called +void systask_pop_data(systask_t* task, size_t size); + +// Runs the task with the given entrypoint and arguments +// +// The task must be not be running when the function is called +// Return `true` in case of success, `false` otherwise +bool systask_push_call(systask_t* task, void* fn, uint32_t arg1, uint32_t arg2, + uint32_t arg3); + +// Terminates the task with the given exit code +// +// If the task is not specified (NULL), it's automatically determined: +// 1) If the function is called in thread mode, the active task will be +// terminated. +// 2) If the function is called in handler mode, the kernel task will be +// terminated even if it is not the active task. +// +// If the terminated task is unprivileged, the kernel task will be scheduled +// next. +void systask_exit(systask_t* task, int exit_code); + +// Terminates the task with an error message +// +// (see `systask_exit()` for more details) +void systask_exit_error(systask_t* task, const char* title, const char* message, + const char* footer); + +// Terminates the task with a fatal error message +// +// (see `systask_exit()` for more details) +void systask_exit_fatal(systask_t* task, const char* message, const char* file, + int line); + +#endif // KERNEL_MODE + +#endif // TREZORHAL_SYSTASK_H diff --git a/core/embed/trezorhal/system.h b/core/embed/trezorhal/system.h new file mode 100644 index 00000000000..07418111220 --- /dev/null +++ b/core/embed/trezorhal/system.h @@ -0,0 +1,68 @@ +/* + * 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_SYSTEM_H +#define TREZORHAL_SYSTEM_H + +#include + +// Initializes the fundamental system services +// (MPU, SysTick, systimer and task scheduler). +// +// `error_handler` is a callback that is called when a kernel task terminates +// with an error +void system_init(systask_error_handler_t error_handler); + +// Terminates the current task normally with the given exit code. +// +// If the current task is the kernel task, the error handler is called with the +// postmortem information. If the task is not the kernel task, the task is +// terminated immediately and the kernel task is scheduled. +void system_exit(int exitcode); + +// Terminates the current task with an error message. +// +// See the notes for `system_exit` regarding the behavior of the error handler +void system_exit_error(const char* title, const char* message, + const char* footer); + +// Terminates the current task with a fatal error message. +// +// See the notes for `system_exit` regarding the behavior of the error handler +void system_exit_fatal(const char* message, const char* file, int line); + +// Returns string representation of the system fault. +const char* system_fault_message(const system_fault_t* fault); + +// Calls the error handler in the emergency mode. +// +// This function is called when the system encounters a critical error +// and needs to perform a useful action (such as displaying an error message) +// before it is reset or shut down. +// +// The function may be called from any context, including interrupt context. +// It completely resets stack pointers, clears the .bss segment, reinitializes +// the .data segment, and calls the `error_handler` callback. +// +// The system will be in a state similar to a reset when `main()` is called +// (but with some hardware peripherals still initialized and running). +__attribute__((noreturn)) void system_emergency_rescue( + systask_error_handler_t error_handler, const systask_postmortem_t* pminfo); + +#endif // TREZORHAL_SYSTEM_H diff --git a/core/embed/trezorhal/systick.h b/core/embed/trezorhal/systick.h new file mode 100644 index 00000000000..71403c06f79 --- /dev/null +++ b/core/embed/trezorhal/systick.h @@ -0,0 +1,100 @@ +/* + * 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_SYSTICK_H +#define TREZORHAL_SYSTICK_H + +#include +#include + +#ifdef KERNEL_MODE + +// Initializes systick subsystem +// +// Before calling this function, none of the other functions +// from this module should be called. +void systick_init(void); + +// Deinitialize systick subsystem +// +// The function should be called before jumping to the +// next bootloader stage or firmware. +void systick_deinit(void); + +// Updates systick subsystem with new system clock frequency +// +// The function should be called after the system clock frequency +// has been changed. +void systick_update_freq(void); + +#endif // KERNEL_MODE + +// ---------------------------------------------------------------------------- +// Tick functions + +// Returns number of system clock cycles since the system start. +// +// Read monotonic counter with high resolution (Cortex-M SysTick clock) +// (On 160MHz CPU, 1 cycles is 1 / 160MHz = 6.25ns) +uint64_t systick_cycles(void); + +// Returns number of microseconds since the system start. +uint64_t systick_us(void); + +// Returns number of ticks (milliseconds) since the system start. +// +// The returned value is a 32-bit unsigned integer that wraps +// around every 49.7 days. +uint32_t systick_ms(void); + +// Converts microseconds to system clock cycles +uint64_t systick_us_to_cycles(uint64_t us); + +// Number of ticks (milliseconds) +typedef uint32_t ticks_t; + +// +#define ticks() systick_ms() + +// Helper function for building expiration time +#define ticks_timeout(timeout) (systick_ms() + (timeout)) + +// Helper function for checking ticks expiration +// +// It copes with the wrap-around of the `ticks_t` type but +// still assumes that the difference between the two ticks +// is less than half of the `ticks_t` range. +#define ticks_expired(ticks) ((int32_t)(systick_ms() - (ticks)) >= 0) + +// ---------------------------------------------------------------------------- +// Delay functions + +// Waits for at least `ms` milliseconds +void systick_delay_ms(uint32_t ms); + +// Waits for at least `us` microseconds +void systick_delay_us(uint64_t us); + +// legacy functions + +static inline uint32_t hal_ticks_ms(void) { return systick_ms(); } +static inline void hal_delay(uint32_t ms) { systick_delay_ms(ms); } +static inline void hal_delay_us(uint64_t us) { systick_delay_us(us); } + +#endif // TREZORHAL_SYSTICK_H diff --git a/core/embed/trezorhal/systimer.h b/core/embed/trezorhal/systimer.h new file mode 100644 index 00000000000..058e585b20a --- /dev/null +++ b/core/embed/trezorhal/systimer.h @@ -0,0 +1,97 @@ +/* + * 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_SYSTIMER_H +#define TREZORHAL_SYSTIMER_H + +#include +#include + +#ifdef KERNEL_MODE + +// Initializes systimer subsystem +// +// Before calling this function, none of the other functions +// from this module should be called. +void systimer_init(void); + +// Deinitialize sytimer subsystem +void systimer_deinit(void); + +// Timer handle +typedef struct systimer systimer_t; + +// Timer callback routine invoked when timer expires +// +// The callback should be as short as possible and should not +// block. It is invoked from the timer interrupt context. +// +// `context` is the pointer passed to `timer_create` +typedef void (*systimer_callback_t)(void* context); + +// Initializes the timer and returns its handle. +// +// There a limited number of timers and `NULL` is returned +// if no timer is available. +systimer_t* systimer_create(systimer_callback_t callback, void* context); + +// Deletes the timer +// +// Timer is unset and its resources are released. +void systimer_delete(systimer_t* timer); + +// Sets the timer to expire in `delay_ms` milliseconds +// +// If the timer is already set, it will be rescheduled. +void systimer_set(systimer_t* timer, uint32_t delay_ms); + +// Sets the timer to expire periodically every `period_ms` milliseconds +// +// If the timer is already set, it will be rescheduled. +void systimer_set_periodic(systimer_t* timer, uint32_t period_ms); + +// Unsets the timer (cancels the expiration) +// +// Timer is not deleted and can be set again. +// +// Returns `true` if the timer was unset before its expiration +// so the callback will not be invoked. +bool systimer_unset(systimer_t* timer); + +// Timer suspension state (opaque type). +// Allows to recursively suspend/resume timer. +typedef bool systimer_key_t; + +// Suspends timer callback invocation +// +// The purpose of this function is to prevent the timer callback +// from being invoked for synchronization purposes. The function +// returns a lock that should be passed to `systimer_resume()` to +// resume the timer callback invocation. +systimer_key_t systimer_suspend(systimer_t* timer); + +// Resumes timer callback invocation +// +// The timer callback invocation is resumed. The `key` should +// be the same as returned by `timer_suspend()`. +void systimer_resume(systimer_t* timer, systimer_key_t key); + +#endif // KERNEL_MODE + +#endif // TREZORHAL_SYSTIMER_H diff --git a/core/embed/trezorhal/tamper.h b/core/embed/trezorhal/tamper.h index 5d3fe12b092..abfbe812668 100644 --- a/core/embed/trezorhal/tamper.h +++ b/core/embed/trezorhal/tamper.h @@ -22,6 +22,8 @@ #include +#ifdef KERNEL_MODE + // Tamper module enables the internal tamper detection on STM32 microcontroller // as well as external tamper input if it's available on the device @@ -35,4 +37,6 @@ void tamper_init(void); // are supported void tamper_test(uint32_t tamper_type); +#endif // KERNEL_MODE + #endif // TREZOR_HAL_TAMPER_H diff --git a/core/embed/trezorhal/touch.h b/core/embed/trezorhal/touch.h index 7b28534a7fc..05843d1e366 100644 --- a/core/embed/trezorhal/touch.h +++ b/core/embed/trezorhal/touch.h @@ -4,6 +4,8 @@ #include #include "secbool.h" +#ifdef KERNEL_MODE + // Initializes the touch driver // // Powers on and initializes touch driver controller. @@ -48,6 +50,8 @@ secbool touch_set_sensitivity(uint8_t value); // The function should not be used together with `touch_get_event()`. secbool touch_activity(void); +#endif // KERNEL_MODE + // Returns the last event in packed 32-bit format // // Returns `0` if there's no event or the driver is not initialized. diff --git a/core/embed/trezorhal/unix/boot_args.c b/core/embed/trezorhal/unix/boot_args.c deleted file mode 100644 index b9765d43e02..00000000000 --- a/core/embed/trezorhal/unix/boot_args.c +++ /dev/null @@ -1,44 +0,0 @@ - -#include "../boot_args.h" -#include -#include - -// The 'g_boot_command_shadow' variable stores the 'command' for the next -// reboot/jumping to the bootloadeer. It may be one of the -// 'BOOT_COMMAND_xxx' values defined in the enumeration, or it could -// be any other value that should be treated as a non-special action, -// in which case the bootloader should behave as if the device was -// just powered up. - -static boot_command_t g_boot_command_shadow; - -// The 'g_boot_args' array stores extra arguments passed -// function boot_args. It sits at section that persists jump to the bootloader. -static boot_args_t g_boot_args; - -void bootargs_set(boot_command_t command, const void* args, size_t args_size) { - // save boot command - g_boot_command_shadow = command; - - size_t copy_size = 0; - // copy arguments up to BOOT_ARGS_MAX_SIZE - if (args != NULL && args_size > 0) { - copy_size = MIN(args_size, BOOT_ARGS_MAX_SIZE); - memcpy(&g_boot_args.raw[0], args, copy_size); - } - - // clear rest of boot_args array - size_t clear_size = BOOT_ARGS_MAX_SIZE - copy_size; - if (clear_size > 0) { - memset(&g_boot_args.raw[copy_size], 0, clear_size); - } -} - -void bootargs_clear() { - g_boot_command_shadow = BOOT_COMMAND_NONE; - memset(&g_boot_args, 0, sizeof(g_boot_args)); -} - -boot_command_t bootargs_get_command() { return g_boot_command_shadow; } - -const boot_args_t* bootargs_get_args() { return &g_boot_args; } diff --git a/core/embed/trezorhal/unix/bootutils.c b/core/embed/trezorhal/unix/bootutils.c new file mode 100644 index 00000000000..1fe3afed888 --- /dev/null +++ b/core/embed/trezorhal/unix/bootutils.c @@ -0,0 +1,64 @@ +/* + * 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 +#include "bootargs.h" +#include "bootutils.h" + +// Holds the 'command' for the next reboot. +static boot_command_t g_boot_command; + +// Holds extra arguments for the command passed to the bootloader. +static boot_args_t g_boot_args; + +void bootargs_set(boot_command_t command, const void* args, size_t args_size) { + // save boot command + g_boot_command = command; + + size_t copy_size = 0; + // copy arguments up to BOOT_ARGS_MAX_SIZE + if (args != NULL && args_size > 0) { + copy_size = MIN(args_size, BOOT_ARGS_MAX_SIZE); + memcpy(&g_boot_args.raw[0], args, copy_size); + } + + // clear rest of boot_args array + size_t clear_size = BOOT_ARGS_MAX_SIZE - copy_size; + if (clear_size > 0) { + memset(&g_boot_args.raw[copy_size], 0, clear_size); + } +} + +boot_command_t bootargs_get_command() { return g_boot_command; } + +const boot_args_t* bootargs_get_args() { return &g_boot_args; } + +void __attribute__((noreturn)) secure_shutdown(void) { + printf("SHUTDOWN\n"); + + // Wait some time to let the user see the displayed + // message before shutting down + hal_delay(3000); + + exit(3); +} diff --git a/core/embed/trezorhal/unix/common.c b/core/embed/trezorhal/unix/common.c index afae59830f5..de06ef6deeb 100644 --- a/core/embed/trezorhal/unix/common.c +++ b/core/embed/trezorhal/unix/common.c @@ -30,24 +30,6 @@ void __attribute__((noreturn)) main_clean_exit(); -void __attribute__((noreturn)) trezor_shutdown(void) { - printf("SHUTDOWN\n"); - - // Wait some time to let the user see the displayed - // message before shutting down - hal_delay(3000); - - exit(3); -} - -void hal_delay(uint32_t ms) { usleep(1000 * ms); } - -uint32_t hal_ticks_ms() { - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - static int SDLCALL emulator_event_filter(void *userdata, SDL_Event *event) { switch (event->type) { case SDL_QUIT: @@ -74,7 +56,3 @@ void emulator_poll_events(void) { SDL_PumpEvents(); SDL_FilterEvents(emulator_event_filter, NULL); } - -uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; - -void collect_hw_entropy(void) { memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); } diff --git a/core/embed/trezorhal/unix/display-unix.c b/core/embed/trezorhal/unix/display-unix.c index 60bbf1acc2a..07a45c82263 100644 --- a/core/embed/trezorhal/unix/display-unix.c +++ b/core/embed/trezorhal/unix/display-unix.c @@ -76,7 +76,7 @@ void display_pixeldata(pixel_color c) { c = (c & 0x8410) ? 0xFFFF : 0x0000; #endif if (!RENDERER) { - display_init(); + display_init_all(); } if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x && PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) { @@ -97,7 +97,7 @@ void display_reset_state() {} void display_init_seq(void) {} -void display_deinit(void) { +void display_exit_handler(void) { SDL_FreeSurface(PREV_SAVED); SDL_FreeSurface(BUFFER); if (BACKGROUND != NULL) { @@ -115,12 +115,12 @@ void display_deinit(void) { SDL_Quit(); } -void display_init(void) { +void display_init_all(void) { if (SDL_Init(SDL_INIT_VIDEO) != 0) { printf("%s\n", SDL_GetError()); error_shutdown("SDL_Init error"); } - atexit(display_deinit); + atexit(display_exit_handler); char *window_title = NULL; char *window_title_alloc = NULL; @@ -197,7 +197,7 @@ void display_init(void) { void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { if (!RENDERER) { - display_init(); + display_init_all(); } PIXELWINDOW.start.x = x0; PIXELWINDOW.start.y = y0; @@ -211,7 +211,7 @@ void display_sync(void) {} void display_refresh(void) { if (!RENDERER) { - display_init(); + display_init_all(); } if (BACKGROUND) { const SDL_Rect r = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; @@ -267,7 +267,7 @@ int display_backlight(int val) { const char *display_save(const char *prefix) { if (!RENDERER) { - display_init(); + display_init_all(); } static int count; static char filename[256]; diff --git a/core/embed/trezorhal/unix/display_driver.c b/core/embed/trezorhal/unix/display_driver.c index ac4d23f2fcb..5cb7b2314f5 100644 --- a/core/embed/trezorhal/unix/display_driver.c +++ b/core/embed/trezorhal/unix/display_driver.c @@ -32,6 +32,8 @@ #define EMULATOR_BORDER 16 typedef struct { + // Set if the driver is initialized + bool initialized; // Current display orientation (0 or 180) int orientation_angle; // Current backlight level ranging from 0 to 255 @@ -52,40 +54,30 @@ typedef struct { } display_driver_t; -static display_driver_t g_display_driver; +static display_driver_t g_display_driver = { + .initialized = false, +}; //!@# TODO get rid of this... int sdl_display_res_x = DISPLAY_RESX, sdl_display_res_y = DISPLAY_RESY; int sdl_touch_offset_x, sdl_touch_offset_y; -void display_deinit(void) { - display_driver_t *drv = &g_display_driver; - - SDL_FreeSurface(drv->prev_saved); - SDL_FreeSurface(drv->buffer); - if (drv->background != NULL) { - SDL_DestroyTexture(drv->background); - } - if (drv->texture != NULL) { - SDL_DestroyTexture(drv->texture); - } - if (drv->renderer != NULL) { - SDL_DestroyRenderer(drv->renderer); - } - if (drv->window != NULL) { - SDL_DestroyWindow(drv->window); - } - SDL_Quit(); +static void display_exit_handler(void) { + display_deinit(DISPLAY_RESET_CONTENT); } -void display_init(void) { +void display_init(display_content_mode_t mode) { display_driver_t *drv = &g_display_driver; + if (drv->initialized) { + return; + } + if (SDL_Init(SDL_INIT_VIDEO) != 0) { printf("%s\n", SDL_GetError()); error_shutdown("SDL_Init error"); } - atexit(display_deinit); + atexit(display_exit_handler); char *window_title = NULL; char *window_title_alloc = NULL; @@ -160,19 +152,42 @@ void display_init(void) { #else drv->orientation_angle = 0; #endif + drv->initialized = true; } -void display_reinit(void) { - // not used -} +void display_deinit(display_content_mode_t mode) { + display_driver_t *drv = &g_display_driver; + + if (!drv->initialized) { + return; + } -void display_finish_actions(void) { - // not used + SDL_FreeSurface(drv->prev_saved); + SDL_FreeSurface(drv->buffer); + if (drv->background != NULL) { + SDL_DestroyTexture(drv->background); + } + if (drv->texture != NULL) { + SDL_DestroyTexture(drv->texture); + } + if (drv->renderer != NULL) { + SDL_DestroyRenderer(drv->renderer); + } + if (drv->window != NULL) { + SDL_DestroyWindow(drv->window); + } + SDL_Quit(); + + drv->initialized = false; } int display_set_backlight(int level) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return 0; + } + #if !USE_BACKLIGHT level = 255; #endif @@ -187,11 +202,21 @@ int display_set_backlight(int level) { int display_get_backlight(void) { display_driver_t *drv = &g_display_driver; + + if (!drv->initialized) { + return 0; + } + return drv->backlight_level; } int display_set_orientation(int angle) { display_driver_t *drv = &g_display_driver; + + if (!drv->initialized) { + return 0; + } + if (angle != drv->orientation_angle) { #if defined ORIENTATION_NSEW if (angle == 0 || angle == 90 || angle == 180 || angle == 270) { @@ -209,6 +234,11 @@ int display_set_orientation(int angle) { int display_get_orientation(void) { display_driver_t *drv = &g_display_driver; + + if (!drv->initialized) { + return 0; + } + return drv->orientation_angle; } @@ -216,25 +246,32 @@ int display_get_orientation(void) { display_fb_info_t display_get_frame_buffer(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + display_fb_info_t fb = { + .ptr = NULL, + .stride = 0, + }; + return fb; + } else { #ifdef DISPLAY_MONO - display_fb_info_t fb = { - .ptr = drv->mono_framebuf, - .stride = DISPLAY_RESX, - }; + display_fb_info_t fb = { + .ptr = drv->mono_framebuf, + .stride = DISPLAY_RESX, + }; #else - display_fb_info_t fb = { - .ptr = drv->buffer->pixels, - .stride = DISPLAY_RESX * sizeof(uint16_t), - }; + display_fb_info_t fb = { + .ptr = drv->buffer->pixels, + .stride = DISPLAY_RESX * sizeof(uint16_t), + }; #endif - - return fb; + return fb; + } } #else // XFRAMEBUFFER void display_wait_for_sync(void) { - // not used + // not implemented in the emulator } #endif @@ -257,8 +294,8 @@ static void copy_mono_framebuf(display_driver_t *drv) { void display_refresh(void) { display_driver_t *drv = &g_display_driver; - if (!drv->renderer) { - display_init(); + if (!drv->initialized) { + return; } #ifdef DISPLAY_MONO @@ -291,15 +328,15 @@ void display_refresh(void) { SDL_RenderPresent(drv->renderer); } -void display_set_compatible_settings(void) { - // not used -} - #ifndef DISPLAY_MONO void display_fill(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y); @@ -311,6 +348,10 @@ void display_fill(const gfx_bitblt_t *bb) { void display_copy_rgb565(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y); @@ -322,6 +363,10 @@ void display_copy_rgb565(const gfx_bitblt_t *bb) { void display_copy_mono1p(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y); @@ -333,6 +378,10 @@ void display_copy_mono1p(const gfx_bitblt_t *bb) { void display_copy_mono4(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = (uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y); @@ -346,6 +395,10 @@ void display_copy_mono4(const gfx_bitblt_t *bb) { void display_fill(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = drv->mono_framebuf + (DISPLAY_RESX * bb_new.dst_y); bb_new.dst_stride = DISPLAY_RESX; @@ -356,6 +409,10 @@ void display_fill(const gfx_bitblt_t *bb) { void display_copy_mono1p(const gfx_bitblt_t *bb) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + gfx_bitblt_t bb_new = *bb; bb_new.dst_row = drv->mono_framebuf + (DISPLAY_RESX * bb_new.dst_y); bb_new.dst_stride = DISPLAY_RESX; @@ -368,8 +425,8 @@ void display_copy_mono1p(const gfx_bitblt_t *bb) { const char *display_save(const char *prefix) { display_driver_t *drv = &g_display_driver; - if (!drv->renderer) { - display_init(); + if (!drv->initialized) { + return NULL; } #ifdef DISPLAY_MONO @@ -404,6 +461,10 @@ const char *display_save(const char *prefix) { void display_clear_save(void) { display_driver_t *drv = &g_display_driver; + if (!drv->initialized) { + return; + } + SDL_FreeSurface(drv->prev_saved); drv->prev_saved = NULL; } diff --git a/core/embed/trezorhal/unix/entropy.c b/core/embed/trezorhal/unix/entropy.c new file mode 100644 index 00000000000..a7a091b6895 --- /dev/null +++ b/core/embed/trezorhal/unix/entropy.c @@ -0,0 +1,28 @@ +/* + * 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 "entropy.h" + +static uint8_t g_hw_entropy[HW_ENTROPY_LEN]; + +void entropy_init(void) { memset(g_hw_entropy, 0, HW_ENTROPY_LEN); } + +void entropy_get(uint8_t *buf) { memcpy(buf, g_hw_entropy, HW_ENTROPY_LEN); } diff --git a/core/embed/trezorhal/unix/fwutils.c b/core/embed/trezorhal/unix/fwutils.c new file mode 120000 index 00000000000..8968a5a0247 --- /dev/null +++ b/core/embed/trezorhal/unix/fwutils.c @@ -0,0 +1 @@ +../stm32f4/fwutils.c \ No newline at end of file diff --git a/core/embed/trezorhal/unix/mpu.c b/core/embed/trezorhal/unix/mpu.c new file mode 100644 index 00000000000..e91a8fa723d --- /dev/null +++ b/core/embed/trezorhal/unix/mpu.c @@ -0,0 +1,30 @@ +/* + * 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 "mpu.h" + +void mpu_init(void) { + // MPU functions are not fully implemented in Emulator +} + +mpu_mode_t mpu_get_mode(void) { return MPU_MODE_DISABLED; } + +mpu_mode_t mpu_reconfig(mpu_mode_t mode) { return MPU_MODE_DISABLED; } + +void mpu_restore(mpu_mode_t mode) {} diff --git a/core/embed/trezorhal/unix/random_delays.c b/core/embed/trezorhal/unix/random_delays.c index 080bc683fe3..b9bcbe5ca4e 100644 --- a/core/embed/trezorhal/unix/random_delays.c +++ b/core/embed/trezorhal/unix/random_delays.c @@ -21,4 +21,4 @@ void wait_random(void) {} -void random_delays_init(void) {} +void rdi_init(void) {} diff --git a/core/embed/trezorhal/unix/random_delays.h b/core/embed/trezorhal/unix/random_delays.h index e720d6a7abb..01191b24cf9 100644 --- a/core/embed/trezorhal/unix/random_delays.h +++ b/core/embed/trezorhal/unix/random_delays.h @@ -20,7 +20,7 @@ #ifndef __TREZORHAL_RANDOM_DELAYS_H__ #define __TREZORHAL_RANDOM_DELAYS_H__ -void random_delays_init(void); +void rdi_init(void); void wait_random(void); #endif diff --git a/core/embed/trezorhal/unix/system.c b/core/embed/trezorhal/unix/system.c new file mode 100644 index 00000000000..728bce47ef6 --- /dev/null +++ b/core/embed/trezorhal/unix/system.c @@ -0,0 +1,107 @@ +/* + * 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 "bootutils.h" +#include "system.h" +#include "systick.h" +#include "systimer.h" + +systask_error_handler_t g_error_handler = NULL; + +void system_init(systask_error_handler_t error_handler) { + g_error_handler = error_handler; + systick_init(); + systimer_init(); +} + +void system_exit(int exitcode) { + if (g_error_handler != NULL) { + systask_postmortem_t pminfo = {0}; + + pminfo.reason = TASK_TERM_REASON_EXIT; + pminfo.exit.code = exitcode; + + if (g_error_handler != NULL) { + g_error_handler(&pminfo); + } + } + + secure_shutdown(); +} + +void system_exit_error(const char* title, const char* message, + const char* footer) { + fprintf(stderr, "ERROR: %s\n", message); + fflush(stderr); + + if (g_error_handler != NULL) { + systask_postmortem_t pminfo = {0}; + + pminfo.reason = TASK_TERM_REASON_ERROR; + strncpy(pminfo.error.title, title, sizeof(pminfo.error.title) - 1); + strncpy(pminfo.error.message, message, sizeof(pminfo.error.message) - 1); + strncpy(pminfo.error.footer, footer, sizeof(pminfo.error.footer) - 1); + + if (g_error_handler != NULL) { + g_error_handler(&pminfo); + } + } + + secure_shutdown(); +} + +void system_exit_fatal(const char* message, const char* file, int line) { + fprintf(stderr, "ERROR: %s\n", message); + if (file) { + fprintf(stderr, "FILE: %s:%d\n", file, line); + } + fflush(stderr); + + if (g_error_handler != NULL) { + systask_postmortem_t pminfo = {0}; + + pminfo.reason = TASK_TERM_REASON_FATAL; + strncpy(pminfo.fatal.file, file, sizeof(pminfo.fatal.file) - 1); + strncpy(pminfo.fatal.expr, message, sizeof(pminfo.fatal.expr) - 1); + pminfo.fatal.line = line; + + if (g_error_handler != NULL) { + g_error_handler(&pminfo); + } + } + + secure_shutdown(); +} + +const char* system_fault_message(const system_fault_t* fault) { + // Not used in simulator + return "(FAULT)"; +} + +void system_emergency_rescue(systask_error_handler_t error_handler, + const systask_postmortem_t* pminfo) { + error_handler(pminfo); + + // We should never reach this point + exit(0); +} diff --git a/core/embed/trezorhal/unix/systick.c b/core/embed/trezorhal/unix/systick.c new file mode 100644 index 00000000000..7515884fd04 --- /dev/null +++ b/core/embed/trezorhal/unix/systick.c @@ -0,0 +1,128 @@ +/* + * 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 +#include + +#include "systick.h" + +// Systick driver state +typedef struct { + // Set if the driver is initialized + bool initialized; + // Instant time [us] of driver initialization + uint64_t initial_time; + // Instant time [us] of driver deinitialization + uint64_t final_time; + +} systick_driver_t; + +static systick_driver_t g_systick_driver = { + .initialized = false, +}; + +// Returns number of microseconds since the os started +static uint64_t get_monotonic_clock(void) { + struct timespec tp; + + clock_gettime(CLOCK_MONOTONIC, &tp); + return tp.tv_sec * 1000000UL + tp.tv_nsec / 1000; +} + +void systick_init(void) { + systick_driver_t* drv = &g_systick_driver; + + if (drv->initialized) { + return; + } + + memset(drv, 0, sizeof(systick_driver_t)); + drv->initial_time = get_monotonic_clock(); + drv->initialized = true; +} + +void systick_deinit(void) { + systick_driver_t* drv = &g_systick_driver; + + if (!drv->initialized) { + return; + } + + // This will ensure that the time return by `systick_ms()` and + // `systick_us()` will not be reset to 0 after the `systick_deinit()` call. + drv->final_time = get_monotonic_clock(); + + drv->initialized = false; +} + +void systick_update_freq(void){}; + +uint32_t systick_ms() { + systick_driver_t* drv = &g_systick_driver; + + if (!drv->initialized) { + systick_init(); // temporary workaround required by rust unit tests + // return drv->final_time / 1000; + } + + return (get_monotonic_clock() - drv->initial_time) / 1000; +} + +uint64_t systick_us(void) { + systick_driver_t* drv = &g_systick_driver; + + if (!drv->initialized) { + systick_init(); // temporary workaround required by rust unit tests + // return drv->final_time; + } + + return get_monotonic_clock() - drv->initial_time; +} + +void systick_delay_us(uint64_t us) { + systick_driver_t* drv = &g_systick_driver; + + if (!drv->initialized) { + systick_init(); // temporary workaround required by rust unit tests + // return; + } + + struct timespec tp; + tp.tv_sec = us / 1000000; + tp.tv_nsec = (us % 1000000) * 1000; + nanosleep(&tp, NULL); +} + +void systick_delay_ms(uint32_t ms) { + systick_driver_t* drv = &g_systick_driver; + + if (!drv->initialized) { + systick_init(); // temporary workaround required by rust unit tests + // return; + } + + struct timespec tp; + tp.tv_sec = ms / 1000; + tp.tv_nsec = (ms % 1000) * 1000000; + nanosleep(&tp, NULL); +} diff --git a/core/embed/trezorhal/unix/systimer.c b/core/embed/trezorhal/unix/systimer.c new file mode 100644 index 00000000000..a678efd982a --- /dev/null +++ b/core/embed/trezorhal/unix/systimer.c @@ -0,0 +1,52 @@ +/* + * 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 "systimer.h" + +// systimer driver state +typedef struct { + // Set if the driver is initialized + bool initialized; +} systimer_driver_t; + +static systimer_driver_t g_systimer_driver = { + .initialized = false, +}; + +void systimer_init(void) { + systimer_driver_t* drv = &g_systimer_driver; + + if (drv->initialized) { + return; + } + + memset(&drv, 0, sizeof(systimer_driver_t)); + drv->initialized = true; +} + +void systimer_deinit(void) { + systimer_driver_t* drv = &g_systimer_driver; + + drv->initialized = false; +} + +// Timer driver is not fully implemented for unix platform +// since not neeeded for the emulator diff --git a/core/embed/trezorhal/unix/usb.c b/core/embed/trezorhal/unix/usb.c index f5c1a00e754..e57f5120cb7 100644 --- a/core/embed/trezorhal/unix/usb.c +++ b/core/embed/trezorhal/unix/usb.c @@ -280,8 +280,6 @@ int usb_webusb_write_blocking(uint8_t iface_num, const uint8_t *buf, return usb_webusb_write(iface_num, buf, len); } -void pendsv_kbd_intr(void) {} - void mp_hal_set_vcp_iface(int iface_num) {} secbool usb_configured(void) { diff --git a/core/embed/trezorhal/xdisplay.h b/core/embed/trezorhal/xdisplay.h index 0fc3a1420dc..80cdcb04d82 100644 --- a/core/embed/trezorhal/xdisplay.h +++ b/core/embed/trezorhal/xdisplay.h @@ -46,18 +46,32 @@ // MIPI - // - STM32U5A9J-DK Discovery Board -// Fully initializes the display controller. -void display_init(void); +#ifdef KERNEL_MODE -// Called in application or bootloader to reinitialize an already initialized -// display controller without any distrubing visible effect (blinking, etc.). -void display_reinit(void); +// Specifies how display content should be handled during +// initialization or deinitialization. +typedef enum { + // Clear the display content + DISPLAY_RESET_CONTENT, + // Retain the display content + DISPLAY_RETAIN_CONTENT +} display_content_mode_t; -// Waits for any backround operations (such as DMA copying) and returns. +// Initializes the display controller. // -// The function provides a barrier when jumping between -// boardloader/bootloader and firmware. -void display_finish_actions(void); +// If `mode` is `DISPLAY_RETAIN_CONTENT`, ensure the driver was previously +// initialized and `display_deinit(DISPLAY_RETAIN_CONTENT)` was called. +void display_init(display_content_mode_t mode); + +// Deinitializes the display controller. +// +// If `mode` is `DISPLAY_RETAIN_CONTENT`, the function waits for +// background operations to complete and disables interrupts, so the +// application can safely proceed to the next boot stage and call +// `display_init(DISPLAY_RETAIN_CONTENT)`. +void display_deinit(display_content_mode_t mode); + +#endif // KERNEL_MODE // Sets display backlight level ranging from 0 (off)..255 (maximum). // @@ -117,12 +131,7 @@ void display_wait_for_sync(void); // swaps the active (currently displayed) and the inactive frame buffers. void display_refresh(void); -// Sets display to the mode compatible with the legacy bootloader code. -// -// This is used when switching between the firmware and the bootloader. -void display_set_compatible_settings(void); - -// Following function define display's bitblt interface. +// Following functions define display's bitblt interface. // // These functions draw directly to to display or to the // currently inactive framebuffer. diff --git a/core/embed/trezorhal/xdisplay_legacy.h b/core/embed/trezorhal/xdisplay_legacy.h index 0fc4d75cc60..fddec1e7e4b 100644 --- a/core/embed/trezorhal/xdisplay_legacy.h +++ b/core/embed/trezorhal/xdisplay_legacy.h @@ -23,12 +23,12 @@ #include #include -// These declarationscode emulates will be removed after the -// final cleanup of display drivers. They are here just to simplify -// integration with the legacy code. +// These declarations will be removed after the final cleanup +// of display drivers. They are here just to simplify integration +// with the legacy code. // -// Most of these function are not called when NEW_RENDERING=1 -// and they are only needed to for succesfully code compilation +// Most of these functions are not called when NEW_RENDERING=1, +// and they are only needed for successful code compilation. #define DISPLAY_FRAMEBUFFER_WIDTH 768 #define DISPLAY_FRAMEBUFFER_HEIGHT 480 diff --git a/core/embed/unix/main.c b/core/embed/unix/main.c index cf8d5a8a0ba..58ef8081313 100644 --- a/core/embed/unix/main.c +++ b/core/embed/unix/main.c @@ -53,6 +53,7 @@ #include "py/repl.h" #include "py/runtime.h" #include "py/stackctrl.h" +#include "systimer.h" #include "touch.h" #include "common.h" @@ -486,7 +487,10 @@ MP_NOINLINE int main_(int argc, char **argv) { pre_process_options(argc, argv); - display_init(); + systick_init(); + systimer_init(); + + display_init(DISPLAY_RESET_CONTENT); #if USE_TOUCH touch_init(); diff --git a/core/embed/unix/main_main.c b/core/embed/unix/main_main.c index f1e28931260..bdc9d561ab3 100644 --- a/core/embed/unix/main_main.c +++ b/core/embed/unix/main_main.c @@ -6,11 +6,12 @@ #endif #include "common.h" +#include "entropy.h" MP_NOINLINE int main_(int argc, char **argv); int main(int argc, char **argv) { - collect_hw_entropy(); + entropy_init(); #ifdef USE_SECP256K1_ZKP ensure(sectrue * (zkp_context_init() == 0), NULL); diff --git a/core/mocks/generated/trezorio/__init__.pyi b/core/mocks/generated/trezorio/__init__.pyi index bd360425ab7..1828d18f3f5 100644 --- a/core/mocks/generated/trezorio/__init__.pyi +++ b/core/mocks/generated/trezorio/__init__.pyi @@ -1,36 +1,6 @@ from typing import * -# extmod/modtrezorio/modtrezorio-flash.h -class FlashOTP: - """ - """ - - def __init__(self) -> None: - """ - """ - - def write(self, block: int, offset: int, data: bytes) -> None: - """ - Writes data to OTP flash - """ - - def read(self, block: int, offset: int, data: bytearray) -> None: - """ - Reads data from OTP flash - """ - - def lock(self, block: int) -> None: - """ - Lock OTP flash block - """ - - def is_locked(self, block: int) -> bool: - """ - Is OTP flash block locked? - """ - - # extmod/modtrezorio/modtrezorio-hid.h class HID: """ diff --git a/core/site_scons/models/D001/discovery.py b/core/site_scons/models/D001/discovery.py index b0533b56793..84592a75815 100644 --- a/core/site_scons/models/D001/discovery.py +++ b/core/site_scons/models/D001/discovery.py @@ -72,7 +72,7 @@ def configure( features_available.append("display_rgb565") if "input" in features_wanted: - sources += ["embed/trezorhal/stm32f4/i2c.c"] + sources += ["embed/trezorhal/stm32f4/i2c_bus.c"] sources += ["embed/trezorhal/stm32f4/touch/stmpe811.c"] features_available.append("touch") diff --git a/core/site_scons/models/D002/discovery2.py b/core/site_scons/models/D002/discovery2.py index cba3537d1f7..9a71eaa294f 100644 --- a/core/site_scons/models/D002/discovery2.py +++ b/core/site_scons/models/D002/discovery2.py @@ -18,7 +18,7 @@ def configure( hw_revision = 0 mcu = "STM32U5A9xx" - linker_script = "stm32u5a" + linker_script = """embed/trezorhal/stm32u5/linker/u5a/{target}.ld""" stm32u5_common_files(env, defines, sources, paths) @@ -57,12 +57,8 @@ def configure( ] if "input" in features_wanted: - sources += [ - "embed/trezorhal/stm32u5/i2c.c", - ] - sources += [ - "embed/trezorhal/stm32u5/touch/sitronix.c", - ] + sources += ["embed/trezorhal/stm32u5/i2c_bus.c"] + sources += ["embed/trezorhal/stm32u5/touch/sitronix.c"] features_available.append("touch") # if "sd_card" in features_wanted: diff --git a/core/site_scons/models/T2B1/trezor_r_v10.py b/core/site_scons/models/T2B1/trezor_r_v10.py index 9cb1723ea6e..1d8951e0c20 100644 --- a/core/site_scons/models/T2B1/trezor_r_v10.py +++ b/core/site_scons/models/T2B1/trezor_r_v10.py @@ -48,8 +48,6 @@ def configure( else: sources += [f"embed/trezorhal/stm32f4/displays/{display}"] - sources += ["embed/trezorhal/stm32f4/i2c.c"] - if "input" in features_wanted: sources += ["embed/trezorhal/stm32f4/button.c"] features_available.append("button") @@ -79,6 +77,7 @@ def configure( if "optiga" in features_wanted: defines += ["USE_OPTIGA=1"] + sources += ["embed/trezorhal/stm32f4/i2c_bus.c"] sources += ["embed/trezorhal/stm32f4/optiga_hal.c"] sources += ["embed/trezorhal/optiga/optiga.c"] sources += ["embed/trezorhal/optiga/optiga_commands.c"] diff --git a/core/site_scons/models/T2T1/trezor_t.py b/core/site_scons/models/T2T1/trezor_t.py index 237db9aa96d..d35ab5152b2 100644 --- a/core/site_scons/models/T2T1/trezor_t.py +++ b/core/site_scons/models/T2T1/trezor_t.py @@ -40,7 +40,9 @@ def configure( defines += [f"HW_REVISION={hw_revision}"] sources += [ "embed/models/T2T1/model_T2T1_layout.c", + "embed/models/T2T1/compat_settings.c", ] + if "new_rendering" in features_wanted: sources += ["embed/trezorhal/xdisplay_legacy.c"] sources += ["embed/trezorhal/stm32f4/xdisplay/st-7789/display_nofb.c"] @@ -80,7 +82,7 @@ def configure( features_available.append("backlight") if "input" in features_wanted: - sources += ["embed/trezorhal/stm32f4/i2c.c"] + sources += ["embed/trezorhal/stm32f4/i2c_bus.c"] sources += ["embed/trezorhal/stm32f4/touch/ft6x36.c"] features_available.append("touch") diff --git a/core/site_scons/models/T3B1/trezor_t3b1_revB.py b/core/site_scons/models/T3B1/trezor_t3b1_revB.py index 67e3f1bfc4a..c20b056b737 100644 --- a/core/site_scons/models/T3B1/trezor_t3b1_revB.py +++ b/core/site_scons/models/T3B1/trezor_t3b1_revB.py @@ -23,7 +23,7 @@ def configure( features_available.append("display_mono") mcu = "STM32U585xx" - linker_script = "stm32u58" + linker_script = """embed/trezorhal/stm32u5/linker/u58/{target}.ld""" stm32u5_common_files(env, defines, sources, paths) @@ -73,7 +73,7 @@ def configure( if "optiga" in features_wanted: defines += ["USE_OPTIGA=1"] - sources += ["embed/trezorhal/stm32u5/i2c.c"] + sources += ["embed/trezorhal/stm32u5/i2c_bus.c"] sources += ["embed/trezorhal/stm32u5/optiga_hal.c"] sources += ["embed/trezorhal/optiga/optiga.c"] sources += ["embed/trezorhal/optiga/optiga_commands.c"] diff --git a/core/site_scons/models/T3T1/trezor_t3t1_revE.py b/core/site_scons/models/T3T1/trezor_t3t1_revE.py index 85edb12c541..1195a7143bf 100644 --- a/core/site_scons/models/T3T1/trezor_t3t1_revE.py +++ b/core/site_scons/models/T3T1/trezor_t3t1_revE.py @@ -27,7 +27,7 @@ def configure( defines += ["XFRAMEBUFFER"] mcu = "STM32U585xx" - linker_script = "stm32u58" + linker_script = """embed/trezorhal/stm32u5/linker/u58/{target}.ld""" stm32u5_common_files(env, defines, sources, paths) @@ -71,7 +71,7 @@ def configure( features_available.append("backlight") if "input" in features_wanted: - sources += ["embed/trezorhal/stm32u5/i2c.c"] + sources += ["embed/trezorhal/stm32u5/i2c_bus.c"] sources += ["embed/trezorhal/stm32u5/touch/ft6x36.c"] sources += ["embed/trezorhal/stm32u5/touch/panels/lx154a2422cpt23.c"] features_available.append("touch") diff --git a/core/site_scons/models/T3T1/trezor_t3t1_v4.py b/core/site_scons/models/T3T1/trezor_t3t1_v4.py index 4d8e3e59bca..63e26c69936 100644 --- a/core/site_scons/models/T3T1/trezor_t3t1_v4.py +++ b/core/site_scons/models/T3T1/trezor_t3t1_v4.py @@ -27,7 +27,7 @@ def configure( defines += ["XFRAMEBUFFER"] mcu = "STM32U585xx" - linker_script = "stm32u58" + linker_script = """embed/trezorhal/stm32u5/linker/u58/{target}.ld""" stm32u5_common_files(env, defines, sources, paths) @@ -46,7 +46,9 @@ def configure( sources += [ "embed/models/T3T1/model_T3T1_layout.c", ] - sources += [f"embed/trezorhal/stm32u5/displays/{display}"] + sources += [ + f"embed/trezorhal/stm32u5/displays/{display}", + ] if "new_rendering" in features_wanted: sources += ["embed/trezorhal/xdisplay_legacy.c"] @@ -73,7 +75,7 @@ def configure( features_available.append("backlight") if "input" in features_wanted: - sources += ["embed/trezorhal/stm32u5/i2c.c"] + sources += ["embed/trezorhal/stm32u5/i2c_bus.c"] sources += ["embed/trezorhal/stm32u5/touch/ft6x36.c"] features_available.append("touch") diff --git a/core/site_scons/models/stm32f4_common.py b/core/site_scons/models/stm32f4_common.py index 3a53387f73d..c90b334f155 100644 --- a/core/site_scons/models/stm32f4_common.py +++ b/core/site_scons/models/stm32f4_common.py @@ -40,23 +40,30 @@ def stm32f4_common_files(env, defines, sources, paths): ] sources += [ + "embed/trezorhal/stm32f4/applet.c", "embed/trezorhal/stm32f4/board_capabilities.c", - "embed/trezorhal/stm32f4/boot_args.c", + "embed/trezorhal/stm32f4/bootutils.c", "embed/trezorhal/stm32f4/common.c", - "embed/trezorhal/stm32f4/fault_handlers.c", + "embed/trezorhal/stm32f4/entropy.c", "embed/trezorhal/stm32f4/flash.c", "embed/trezorhal/stm32f4/flash_otp.c", + "embed/trezorhal/stm32f4/fwutils.c", "embed/trezorhal/stm32f4/lowlevel.c", "embed/trezorhal/stm32f4/monoctr.c", "embed/trezorhal/stm32f4/mpu.c", "embed/trezorhal/stm32f4/platform.c", "embed/trezorhal/stm32f4/secret.c", + "embed/trezorhal/stm32f4/syscall.c", + "embed/trezorhal/stm32f4/syscall_dispatch.c", + "embed/trezorhal/stm32f4/syscall_stubs.c", + "embed/trezorhal/stm32f4/system.c", + "embed/trezorhal/stm32f4/systask.c", "embed/trezorhal/stm32f4/systick.c", - "embed/trezorhal/stm32f4/supervise.c", + "embed/trezorhal/stm32f4/systimer.c", "embed/trezorhal/stm32f4/time_estimate.c", "embed/trezorhal/stm32f4/random_delays.c", "embed/trezorhal/stm32f4/rng.c", - "embed/trezorhal/stm32f4/vectortable.s", + "embed/trezorhal/stm32f4/vectortable.S", ] # boardloader needs separate assembler for some function unencumbered by various FW+bootloader hacks @@ -64,12 +71,12 @@ def stm32f4_common_files(env, defines, sources, paths): env_constraints = env.get("CONSTRAINTS") if env_constraints and "limited_util_s" in env_constraints: sources += [ - "embed/trezorhal/stm32f4/limited_util.s", + "embed/trezorhal/stm32f4/limited_util.S", ] else: sources += [ - "embed/trezorhal/stm32f4/util.s", + "embed/trezorhal/stm32f4/util.S", ] env.get("ENV")["SUFFIX"] = "stm32f4" - env.get("ENV")["LINKER_SCRIPT"] = "stm32f4" + env.get("ENV")["LINKER_SCRIPT"] = """embed/trezorhal/stm32f4/linker/{target}.ld""" diff --git a/core/site_scons/models/stm32u5_common.py b/core/site_scons/models/stm32u5_common.py index ff08f108c77..c62c066fed1 100644 --- a/core/site_scons/models/stm32u5_common.py +++ b/core/site_scons/models/stm32u5_common.py @@ -49,12 +49,14 @@ def stm32u5_common_files(env, defines, sources, paths): ] sources += [ + "embed/trezorhal/stm32u5/applet.c", "embed/trezorhal/stm32u5/board_capabilities.c", - "embed/trezorhal/stm32u5/boot_args.c", + "embed/trezorhal/stm32u5/bootutils.c", "embed/trezorhal/stm32u5/common.c", - "embed/trezorhal/stm32u5/fault_handlers.c", + "embed/trezorhal/stm32u5/entropy.c", "embed/trezorhal/stm32u5/flash.c", "embed/trezorhal/stm32u5/flash_otp.c", + "embed/trezorhal/stm32u5/fwutils.c", "embed/trezorhal/stm32u5/lowlevel.c", "embed/trezorhal/stm32u5/hash_processor.c", "embed/trezorhal/stm32u5/monoctr.c", @@ -62,14 +64,19 @@ def stm32u5_common_files(env, defines, sources, paths): "embed/trezorhal/stm32u5/platform.c", "embed/trezorhal/stm32u5/secret.c", "embed/trezorhal/stm32u5/secure_aes.c", + "embed/trezorhal/stm32u5/syscall.c", + "embed/trezorhal/stm32u5/syscall_dispatch.c", + "embed/trezorhal/stm32u5/syscall_stubs.c", + "embed/trezorhal/stm32u5/system.c", + "embed/trezorhal/stm32u5/systask.c", "embed/trezorhal/stm32u5/systick.c", - "embed/trezorhal/stm32f4/supervise.c", + "embed/trezorhal/stm32u5/systimer.c", "embed/trezorhal/stm32u5/random_delays.c", "embed/trezorhal/stm32u5/rng.c", "embed/trezorhal/stm32u5/tamper.c", "embed/trezorhal/stm32u5/time_estimate.c", "embed/trezorhal/stm32u5/trustzone.c", - "embed/trezorhal/stm32u5/vectortable.s", + "embed/trezorhal/stm32u5/vectortable.S", ] # boardloader needs separate assembler for some function unencumbered by various FW+bootloader hacks @@ -77,11 +84,11 @@ def stm32u5_common_files(env, defines, sources, paths): env_constraints = env.get("CONSTRAINTS") if env_constraints and "limited_util_s" in env_constraints: sources += [ - "embed/trezorhal/stm32u5/limited_util.s", + "embed/trezorhal/stm32u5/limited_util.S", ] else: sources += [ - "embed/trezorhal/stm32u5/util.s", + "embed/trezorhal/stm32u5/util.S", ] env.get("ENV")["SUFFIX"] = "stm32u5" diff --git a/core/site_scons/tools.py b/core/site_scons/tools.py index 315ca5cef76..85ac138eb12 100644 --- a/core/site_scons/tools.py +++ b/core/site_scons/tools.py @@ -99,12 +99,12 @@ def get_bindgen_defines( return ",".join(rest_defs) -def embed_binary(obj_program, env, section, target_, file): +def embed_compressed_binary(obj_program, env, section, target_, file, build): _in = f"embedded_{section}.bin.deflated" def redefine_sym(name): src = ( - "_binary_build_firmware_" + f"_binary_build_{build}_" + _in.replace("/", "_").replace(".", "_") + "_" + name @@ -140,3 +140,14 @@ def compress_action(target, source, env): ) env.Depends(obj_program, compress) + + +def embed_raw_binary(obj_program, env, section, target_, file): + obj_program.extend( + env.Command( + target=target_, + source=file, + action="$OBJCOPY -I binary -O elf32-littlearm -B arm" + f" --rename-section .data=.{section}" + " $SOURCE $TARGET", + ) + ) diff --git a/core/tests/production_tests/main.py b/core/tests/production_tests/main.py deleted file mode 100644 index 5a806f0ebd8..00000000000 --- a/core/tests/production_tests/main.py +++ /dev/null @@ -1,190 +0,0 @@ -import trezorio as io -import trezorui as ui -import utime - -usb_vcp = io.VCP( - iface_num=0x00, - data_iface_num=0x01, - ep_in=0x01, - ep_out=0x01, - ep_cmd=0x02, -) - -usb = io.USB( - vendor_id=0x1209, - product_id=0x53C1, - release_num=0x0200, - manufacturer="SatoshiLabs", - product="TREZOR", - serial_number="000000000000000000000000", - usb21_landing=False, -) - -usb.add(usb_vcp) - -usb.open() - -d = ui.Display() -otp = io.FlashOTP() -sd = io.SDCard() -sbu = io.SBU() - - -def test_display(colors): - d.clear() - m = { - "R": 0xF800, - "G": 0x07E0, - "B": 0x001F, - "W": 0xFFFF, - } - w = 240 // len(colors) - for i, c in enumerate(colors): - c = m.get(c, 0x0000) - d.bar(i * w, 0, i * w + w, 240, c) - d.refresh() - print("OK") - - -def test_touch(v): - d.clear() - c, t = int(v[0]), int(v[1]) - deadline = utime.ticks_add(utime.ticks_us(), t * 1000000) - if c == 1: - d.bar(0, 0, 120, 120, 0xFFFF) - elif c == 2: - d.bar(120, 0, 120, 120, 0xFFFF) - elif c == 3: - d.bar(120, 120, 120, 120, 0xFFFF) - else: - d.bar(0, 120, 120, 120, 0xFFFF) - d.refresh() - r = [0, 0] - # flush all events - while io.poll([io.TOUCH], r, 10000): - pass - # wait for event - touch = False - while True: - if not touch: - if ( - io.poll([io.TOUCH], r, 10000) - and r[0] == io.TOUCH - and r[1][0] == io.TOUCH_START - ): - touch = True - else: - if ( - io.poll([io.TOUCH], r, 10000) - and r[0] == io.TOUCH - and r[1][0] == io.TOUCH_END - ): - print(f"OK {r[1][1]} {r[1][2]}") - break - if utime.ticks_us() > deadline: - print("ERROR TIMEOUT") - break - # flush all events - while io.poll([io.TOUCH], r, 10000): - pass - d.clear() - d.refresh() - - -def test_pwm(v): - d.backlight(int(v)) - d.refresh() - print("OK") - - -def test_sd(): - if sd.present(): - sd.power(True) - buf1 = bytearray(8 * 1024) - try: - sd.read(0, buf1) - except OSError: - print("ERROR READING DATA") - sd.power(False) - return - try: - sd.write(0, buf1) - except OSError: - print("ERROR WRITING DATA") - sd.power(False) - return - buf2 = bytearray(8 * 1024) - try: - sd.read(0, buf2) - except OSError: - print("ERROR READING DATA") - sd.power(False) - return - if buf1 == buf2: - print("OK") - else: - print("ERROR DATA MISMATCH") - sd.power(False) - else: - print("ERROR NOCARD") - - -def test_sbu(v): - sbu1 = v[0] == "1" - sbu2 = v[1] == "1" - sbu.set(sbu1, sbu2) - print("OK") - - -def test_otp_read(): - data = bytearray(32) - otp.read(0, 0, data) - data = bytes(data).rstrip(b"\x00\xff").decode() - print("OK", data) - - -def test_otp_write(v): - if len(v) < 32: - v = v + "\x00" * (32 - len(v)) - data = v[:32].encode() - otp.write(0, 0, data) - otp.lock(0) - print("OK") - - -d.clear() - -while True: - - try: - line = input() - - if line == "PING": - print("OK") - - elif line.startswith("DISP "): - test_display(line[5:]) - - elif line.startswith("TOUCH "): - test_touch(line[6:]) - - elif line.startswith("PWM "): - test_pwm(line[4:]) - - elif line == "SD": - test_sd() - - elif line.startswith("SBU "): - test_sbu(line[4:]) - - elif line.startswith("OTP READ"): - test_otp_read() - - elif line.startswith("OTP WRITE "): - test_otp_write(line[10:]) - - else: - print("UNKNOWN") - - except Exception as ex: - print("ERROR", ex) diff --git a/core/tools/README.md b/core/tools/README.md index 14fb0baf735..be1f263054c 100644 --- a/core/tools/README.md +++ b/core/tools/README.md @@ -76,8 +76,9 @@ A Python package that exposes certain functionalities as CLI commands. `headertool` and `combine_firmware` live here, more may be moved or added. -One additional tool is `layout_parser`, which is used to extract memory layout -information from a model `.h` file. +Additional tools are `layout_parser`, which is used to extract memory layout +information from a model `.h` file, and related tool `lsgen` to generate linker script files +from the model `.h`. ### `alloc.py` diff --git a/core/tools/pyproject.toml b/core/tools/pyproject.toml index 125aaf6dd21..ece3ebf6c95 100644 --- a/core/tools/pyproject.toml +++ b/core/tools/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "trezor_core_tools" -version = "0.1.0" +version = "0.1.1" description = "Collection of CLI tools for trezor-core development" authors = ["matejcik "] license = "GPLv3+" @@ -17,4 +17,5 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] headertool = "trezor_core_tools.headertool:cli" layout_parser = "trezor_core_tools.layout_parser:main" +lsgen = "trezor_core_tools.lsgen:main" combine_firmware = "trezor_core_tools.combine_firmware:main" diff --git a/core/tools/trezor_core_tools/common.py b/core/tools/trezor_core_tools/common.py index 7a4f2f5be7f..74fdb6f6348 100644 --- a/core/tools/trezor_core_tools/common.py +++ b/core/tools/trezor_core_tools/common.py @@ -19,3 +19,7 @@ def get_layout_for_model(model: str) -> Path: model = MODELS_DICT.get(model, model) return MODELS_DIR / model / f"model_{model}.h" + +def get_linkerscript_for_model(model: str) -> Path: + model = MODELS_DICT.get(model, model) + return MODELS_DIR / model / f"memory.ld" diff --git a/core/tools/trezor_core_tools/layout_parser.py b/core/tools/trezor_core_tools/layout_parser.py index 13b2e433039..aec22a1e1ec 100644 --- a/core/tools/trezor_core_tools/layout_parser.py +++ b/core/tools/trezor_core_tools/layout_parser.py @@ -19,7 +19,12 @@ def find_all_values(model: str) -> dict[str, int]: layout = get_layout_for_model(model) values = {} + begin = False for line in open(layout): + if not begin: + if line.startswith("// SHARED"): + begin = True + continue match = re.match(SEARCH_PATTERN, line) if match is not None: name, value = match.groups() diff --git a/core/tools/trezor_core_tools/lsgen.py b/core/tools/trezor_core_tools/lsgen.py new file mode 100644 index 00000000000..36d7d7e7229 --- /dev/null +++ b/core/tools/trezor_core_tools/lsgen.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import click + +from .common import get_linkerscript_for_model, MODELS_DIR +from .layout_parser import find_all_values + + +warning = """/* Auto-generated file, do not edit.*/ + +""" + +@click.command() +@click.option("--check", is_flag=True) +def main(check: bool) -> None: + + models = list(MODELS_DIR.iterdir()) + models = [model for model in models if model.is_dir()] + + for model in models: + values = find_all_values(model.name) + content = warning + input = get_linkerscript_for_model(model.name) + print(f"Processing {input}") + for name, value in values.items(): + content += f"{name} = {hex(value)};\n" + if not check: + input.write_text(content) + else: + actual = input.read_text() + if content != actual: + raise click.ClickException(f"{input} differs from expected") + + +if __name__ == "__main__": + main() diff --git a/poetry.lock b/poetry.lock index 74500faa4f5..4ffb20f24de 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1583,7 +1583,7 @@ url = "python" [[package]] name = "trezor-core-tools" -version = "0.1.0" +version = "0.1.1" description = "Collection of CLI tools for trezor-core development" optional = false python-versions = "^3.8" diff --git a/storage/storage.c b/storage/storage.c index fe36b52e063..cff331cfb3d 100644 --- a/storage/storage.c +++ b/storage/storage.c @@ -557,7 +557,7 @@ static void derive_kek_v4(const uint8_t *pin, size_t pin_len, uint8_t pre_kek[SHA256_DIGEST_LENGTH] = {0}; pbkdf2_hmac_sha256_Final(&ctx, pre_kek); ensure(secure_aes_ecb_encrypt_hw(pre_kek, SHA256_DIGEST_LENGTH, kek, - SECURE_AES_KEY_XORK), + SECURE_AES_KEY_XORK_SN), "secure_aes derive kek failed"); memzero(pre_kek, sizeof(pre_kek)); #else @@ -615,7 +615,7 @@ static void stretch_pin(const uint8_t *pin, size_t pin_len, uint8_t stretched_pin_tmp[SHA256_DIGEST_LENGTH] = {0}; pbkdf2_hmac_sha256_Final(&ctx, stretched_pin_tmp); ensure(secure_aes_ecb_encrypt_hw(stretched_pin_tmp, SHA256_DIGEST_LENGTH, - stretched_pin, SECURE_AES_KEY_XORK), + stretched_pin, SECURE_AES_KEY_XORK_SN), "secure_aes pin stretch failed"); memzero(stretched_pin_tmp, sizeof(stretched_pin_tmp)); #else