diff --git a/Makefile b/Makefile index 0ad3eeeb..912f9ed2 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ BUILD_DIR = build BOARDLOADER_BUILD_DIR = $(BUILD_DIR)/boardloader BOOTLOADER_BUILD_DIR = $(BUILD_DIR)/bootloader PRODTEST_BUILD_DIR = $(BUILD_DIR)/prodtest +REFLASH_BUILD_DIR = $(BUILD_DIR)/reflash FIRMWARE_BUILD_DIR = $(BUILD_DIR)/firmware UNIX_BUILD_DIR = $(BUILD_DIR)/unix @@ -89,6 +90,11 @@ build_bootloader: ## build bootloader build_prodtest: ## build production test firmware $(SCONS) CFLAGS="$(CFLAGS)" $(PRODTEST_BUILD_DIR)/prodtest.bin +build_reflash: ## build reflash firmware + reflash image + $(SCONS) CFLAGS="$(CFLAGS)" $(REFLASH_BUILD_DIR)/reflash.bin + 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: res build_cross ## build firmware with frozen modules $(SCONS) CFLAGS="$(CFLAGS)" $(FIRMWARE_BUILD_DIR)/firmware.bin @@ -114,6 +120,9 @@ clean_bootloader: ## clean bootloader build clean_prodtest: ## clean prodtest build rm -rf $(PRODTEST_BUILD_DIR) +clean_reflash: ## clean reflash build + rm -rf $(REFLASH_BUILD_DIR) + clean_firmware: ## clean firmware build rm -rf $(FIRMWARE_BUILD_DIR) diff --git a/SConscript.reflash b/SConscript.reflash new file mode 100644 index 00000000..5e576f84 --- /dev/null +++ b/SConscript.reflash @@ -0,0 +1,159 @@ +# pylint: disable=E0602 + +import os + +CCFLAGS_MOD = '' +CPPPATH_MOD = [] +CPPDEFINES_MOD = [] +SOURCE_MOD = [] + +# modtrezorui +CPPDEFINES_MOD += [ + 'TREZOR_FONT_MONO_DISABLE', + 'TREZOR_FONT_NORMAL_DISABLE', + ('QR_MAX_VERSION', '0'), +] +SOURCE_MOD += [ + 'embed/extmod/modtrezorui/display.c', + 'embed/extmod/modtrezorui/inflate.c', + 'embed/extmod/modtrezorui/font_bitmap.c', + 'embed/extmod/modtrezorui/font_roboto_bold_20.c', + 'embed/extmod/modtrezorui/trezor-qrenc/qr_encode.c', +] + +SOURCE_STMHAL = [ + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_can.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dac_ex.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dac.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd_ex.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rng.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rtc_ex.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rtc.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_sd.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_sram.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_fmc.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.c', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c', +] + +SOURCE_REFLASH = [ + 'embed/reflash/startup.s', + 'embed/reflash/header.S', + 'embed/reflash/main.c', +] + +SOURCE_TREZORHAL = [ + 'embed/trezorhal/common.c', + 'embed/trezorhal/flash.c', + 'embed/trezorhal/mini_printf.c', + 'embed/trezorhal/rng.c', + 'embed/trezorhal/sbu.c', + 'embed/trezorhal/sdcard.c', + 'embed/trezorhal/stm32.c', + 'embed/trezorhal/touch.c', + 'embed/trezorhal/usb.c', + 'embed/trezorhal/usbd_conf.c', + 'embed/trezorhal/usbd_core.c', + 'embed/trezorhal/usbd_ctlreq.c', + 'embed/trezorhal/usbd_ioreq.c', + 'embed/trezorhal/util.s', + 'embed/trezorhal/vectortable.s', +] + +env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0'))) + +env.Replace( + AS='arm-none-eabi-as', + AR='arm-none-eabi-ar', + CC='arm-none-eabi-gcc', + LINK='arm-none-eabi-ld', + SIZE='arm-none-eabi-size', + STRIP='arm-none-eabi-strip', + OBJCOPY='arm-none-eabi-objcopy', ) + +env.Replace( + CCFLAGS='-Os ' + '-g3 ' + '-nostdlib ' + '-std=gnu99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -fno-common ' + '-mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard ' + '-fsingle-precision-constant -fdata-sections -ffunction-sections ' + '-fstack-protector-all -ffreestanding ' + + CCFLAGS_MOD, + CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', + LINKFLAGS='-nostdlib -T embed/reflash/memory.ld --gc-sections -Map=build/reflash/reflash.map --warn-common', + CPPPATH=[ + 'embed/reflash', + 'embed/trezorhal', + 'embed/extmod/modtrezorui', + 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc', + 'vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include', + 'vendor/micropython/lib/cmsis/inc', + 'vendor/micropython/ports/stm32', + ] + CPPPATH_MOD, + CPPDEFINES=[ + 'TREZOR_STM32', + 'MCU_SERIES_F4', + 'STM32F427xx', + ('STM32_HAL_H', '""'), + ] + CPPDEFINES_MOD, + ASFLAGS='-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16', + ASPPFLAGS='$CFLAGS $CCFLAGS', ) + +env.Replace( + BINCTL='tools/binctl', + COMBINE_SIGN='tools/combine_sign', +) + +# +# Program objects +# + +obj_program = [] +obj_program += env.Object(source=SOURCE_MOD) +obj_program += env.Object(source=SOURCE_REFLASH) +obj_program += env.Object(source=SOURCE_STMHAL) +obj_program += env.Object(source=SOURCE_TREZORHAL) + +obj_program.extend( + env.Command( + target='embed/reflash/vendorheader.o', + source='embed/firmware/vendorheader.bin', + action='$OBJCOPY -I binary -O elf32-littlearm -B arm' + ' --rename-section .data=.vendorheader,alloc,load,readonly,contents' + ' $SOURCE $TARGET', )) + +program_elf = env.Command( + target='reflash.elf', + source=obj_program, + action= + '$LINK -o $TARGET $LINKFLAGS $SOURCES `$CC $CFLAGS $CCFLAGS $_CCCOMCOM -print-libgcc-file-name` `$CC $CFLAGS $CCFLAGS $_CCCOMCOM -print-file-name=libc_nano.a`', +) + +program_bin = env.Command( + target='reflash.bin', + source=program_elf, + action=[ + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET', + '$BINCTL $TARGET -h', + 'dd if=$TARGET of=build/reflash/header.tosign bs=1 count=1024 skip=`wc -c < embed/firmware/vendorheader.bin | tr -d " "`', + '$BINCTL $TARGET -s 1:2 `$COMBINE_SIGN firmware build/reflash/header.tosign 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`', + ], ) diff --git a/SConstruct b/SConstruct index a1661534..4eccd20b 100644 --- a/SConstruct +++ b/SConstruct @@ -2,6 +2,7 @@ SConscript('SConscript.boardloader', variant_dir='build/boardloader', duplicate=False) SConscript('SConscript.bootloader', variant_dir='build/bootloader', duplicate=False) +SConscript('SConscript.reflash', variant_dir='build/reflash', duplicate=False) SConscript('SConscript.prodtest', variant_dir='build/prodtest', duplicate=False) SConscript('SConscript.firmware', variant_dir='build/firmware', duplicate=False) SConscript('SConscript.unix', variant_dir='build/unix', duplicate=False) diff --git a/embed/reflash/header.S b/embed/reflash/header.S new file mode 100644 index 00000000..5f303986 --- /dev/null +++ b/embed/reflash/header.S @@ -0,0 +1,24 @@ + .syntax unified + +#include "version.h" + + .section .header, "a" + + .type g_header, %object + .size g_header, .-g_header + +g_header: + .byte 'T','R','Z','F' // magic + .word g_header_end - g_header // hdrlen + .word 0 // expiry + .word _codelen // codelen + .byte VERSION_MAJOR // vmajor + .byte VERSION_MINOR // vminor + .byte VERSION_PATCH // vpatch + .byte VERSION_BUILD // vbuild + . = . + 12 // reserved + . = . + 512 // hash1 ... hash16 + . = . + 415 // reserved + .byte 0 // sigmask + . = . + 64 // sig +g_header_end: diff --git a/embed/reflash/main.c b/embed/reflash/main.c new file mode 100644 index 00000000..4cce1869 --- /dev/null +++ b/embed/reflash/main.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) Jan Pochyla, SatoshiLabs + * + * Licensed under TREZOR License + * see LICENSE file for details + */ + +#include +#include +#include + +#include STM32_HAL_H + +#include "common.h" +#include "display.h" +#include "flash.h" +#include "image.h" +#include "rng.h" +#include "sbu.h" +#include "sdcard.h" +#include "secbool.h" +#include "touch.h" + +static void progress_callback(int pos, int len) +{ + display_printf("."); +} + +static void flash_from_sdcard(uint32_t target, uint32_t source, uint32_t length) +{ + static uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)]; + + ensure( + sectrue * (source % SDCARD_BLOCK_SIZE == 0), + "source not a multiple of block size"); + ensure( + sectrue * (length % SDCARD_BLOCK_SIZE == 0), + "length not a multiple of block size"); + + for (uint32_t i = 0; i < length / SDCARD_BLOCK_SIZE; i++) { + display_printf("read %d\n", (unsigned int)(i + source / SDCARD_BLOCK_SIZE)); + + ensure( + sdcard_read_blocks(buf, i + source / SDCARD_BLOCK_SIZE, 1), + "sdcard_read_blocks"); + + for (uint32_t j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) { + ensure( + flash_write_word(target + i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t), buf[j]), + "flash_write_word"); + } + } +} + +int main(void) +{ + sdcard_init(); + touch_init(); + + display_orientation(0); + display_clear(); + display_backlight(255); + + ensure( + sdcard_is_present(), + "sdcard_is_present"); + + display_printf("updating boardloader + bootloader\n"); + + uint8_t sectors[] = { + FLASH_SECTOR_BOARDLOADER_START, + 1, + FLASH_SECTOR_BOARDLOADER_END, + FLASH_SECTOR_BOOTLOADER, + }; + display_printf("erasing sectors"); + ensure( + flash_erase_sectors(sectors, sizeof(sectors), progress_callback), + "flash_erase_sectors"); + display_printf("\n"); + display_printf("erased\n"); + + ensure( + flash_unlock(), + "flash_unlock"); + + sdcard_power_on(); + +#define BOARDLOADER_SIZE (3 * 16 * 1024) +#define BOOTLOADER_SIZE (128 * 1024) + + flash_from_sdcard(BOARDLOADER_START, 0, BOARDLOADER_SIZE); + flash_from_sdcard(BOOTLOADER_START, BOARDLOADER_SIZE, BOOTLOADER_SIZE); + + display_printf("done\n"); + sdcard_power_off(); + flash_lock(); + + return 0; +} diff --git a/embed/reflash/memory.ld b/embed/reflash/memory.ld new file mode 100644 index 00000000..326c64ed --- /dev/null +++ b/embed/reflash/memory.ld @@ -0,0 +1,71 @@ +/* TREZORv2 firmware linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x08040000, LENGTH = 768K + CCMRAM (wal) : ORIGIN = 0x10000000, LENGTH = 64K + 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); + +/* 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 +} diff --git a/embed/reflash/startup.s b/embed/reflash/startup.s new file mode 100644 index 00000000..cbcfb67b --- /dev/null +++ b/embed/reflash/startup.s @@ -0,0 +1,41 @@ + .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, =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 + + .end diff --git a/embed/reflash/version.h b/embed/reflash/version.h new file mode 100644 index 00000000..a62341fe --- /dev/null +++ b/embed/reflash/version.h @@ -0,0 +1,4 @@ +#define VERSION_MAJOR 0 +#define VERSION_MINOR 1 +#define VERSION_PATCH 0 +#define VERSION_BUILD 0