From 78b401785945e573fede38026b4888557b3aaa66 Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Sun, 14 Apr 2024 10:04:44 +0200 Subject: [PATCH] feat(core): add support for T3B1 --- core/.changelog.d/3728.added | 1 + core/Makefile | 5 + core/SConscript.bootloader | 4 +- core/SConscript.bootloader_ci | 2 +- core/SConscript.bootloader_emu | 4 +- core/SConscript.firmware | 4 +- core/SConscript.prodtest | 2 +- core/SConscript.reflash | 2 +- core/SConscript.unix | 4 +- .../bootloaders/bootloader_T3B1_qa.bin | Bin 0 -> 93184 bytes core/embed/firmware/memory_T3B1.ld | 1 + core/embed/models/T3B1/boards/t3b1-unix.h | 24 +++ .../models/T3B1/boards/trezor_t3b1_revB.h | 63 ++++++++ core/embed/models/T3B1/model_T3B1.h | 50 +++++++ core/embed/models/T3B1/model_T3B1_layout.c | 96 ++++++++++++ core/embed/models/model.h | 2 + core/embed/trezorhal/stm32u5/button.c | 1 + .../trezorhal/stm32u5/consumption_mask.c | 140 ++++++++++++++++++ .../stm32u5/displays/vg-2864ksweg01.c | 1 + .../stm32u5/displays/vg-2864ksweg01.h | 1 + core/embed/trezorhal/stm32u5/platform.c | 3 + .../trezorhal/stm32u5/stm32u5xx_hal_conf.h | 2 +- core/embed/trezorhal/unix/flash.c | 6 +- .../T3B1/vendor_dev_DO_NOT_SIGN.json | 20 +++ ...endorheader_dev_DO_NOT_SIGN_signed_dev.bin | Bin 0 -> 512 bytes .../vendorheader_dev_DO_NOT_SIGN_unsigned.bin | Bin 0 -> 512 bytes core/embed/vendorheader/generate.sh | 2 +- core/site_scons/models/T3B1/__init__.py | 30 ++++ core/site_scons/models/T3B1/emulator.py | 49 ++++++ .../models/T3B1/trezor_t3b1_revB.py | 85 +++++++++++ core/site_scons/models/__init__.py | 4 +- python/.changelog.d/3728.added | 1 + python/src/trezorlib/firmware/models.py | 35 +++++ python/src/trezorlib/models.py | 11 +- 34 files changed, 637 insertions(+), 18 deletions(-) create mode 100644 core/.changelog.d/3728.added create mode 100755 core/embed/firmware/bootloaders/bootloader_T3B1_qa.bin create mode 120000 core/embed/firmware/memory_T3B1.ld create mode 100644 core/embed/models/T3B1/boards/t3b1-unix.h create mode 100644 core/embed/models/T3B1/boards/trezor_t3b1_revB.h create mode 100644 core/embed/models/T3B1/model_T3B1.h create mode 100644 core/embed/models/T3B1/model_T3B1_layout.c create mode 120000 core/embed/trezorhal/stm32u5/button.c create mode 100644 core/embed/trezorhal/stm32u5/consumption_mask.c create mode 120000 core/embed/trezorhal/stm32u5/displays/vg-2864ksweg01.c create mode 120000 core/embed/trezorhal/stm32u5/displays/vg-2864ksweg01.h create mode 100644 core/embed/vendorheader/T3B1/vendor_dev_DO_NOT_SIGN.json create mode 100644 core/embed/vendorheader/T3B1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin create mode 100644 core/embed/vendorheader/T3B1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin create mode 100644 core/site_scons/models/T3B1/__init__.py create mode 100644 core/site_scons/models/T3B1/emulator.py create mode 100644 core/site_scons/models/T3B1/trezor_t3b1_revB.py create mode 100644 python/.changelog.d/3728.added diff --git a/core/.changelog.d/3728.added b/core/.changelog.d/3728.added new file mode 100644 index 0000000000..5f87842afa --- /dev/null +++ b/core/.changelog.d/3728.added @@ -0,0 +1 @@ +Added support for T3B1 diff --git a/core/Makefile b/core/Makefile index 22c933b691..4e53bac5f5 100644 --- a/core/Makefile +++ b/core/Makefile @@ -63,6 +63,11 @@ MCU = STM32U5 OPENOCD_TARGET = target/stm32u5x.cfg LAYOUT_FILE = embed/models/T3T1/model_T3T1.h MODEL_FEATURE = model_mercury +else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),T3B1)) +MCU = STM32U5 +OPENOCD_TARGET = target/stm32u5x.cfg +LAYOUT_FILE = embed/models/T3B1/model_T3B1.h +MODEL_FEATURE = model_tr else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),DISC1)) MCU = STM32F4 LAYOUT_FILE = embed/models/D001/model_D001.h diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 889b2d085d..b9d700d832 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -36,7 +36,7 @@ CPPDEFINES_HAL = [] SOURCE_HAL = [] PATH_HAL = [] -if TREZOR_MODEL in ('R', ): +if TREZOR_MODEL in ('R', 'T3B1'): FONT_NORMAL='Font_PixelOperator_Regular_8' FONT_DEMIBOLD='Font_PixelOperator_Regular_8' FONT_BOLD='Font_PixelOperator_Bold_8' @@ -255,7 +255,7 @@ def cargo_build(): profile = '' if TREZOR_MODEL in ("1",): features = ["model_t1"] - elif TREZOR_MODEL in ("R",): + elif TREZOR_MODEL in ("R", "T3B1"): features = ["model_tr"] elif TREZOR_MODEL in ("T3T1",): features = ["model_mercury"] diff --git a/core/SConscript.bootloader_ci b/core/SConscript.bootloader_ci index 56e3b136d7..04e8be1c11 100644 --- a/core/SConscript.bootloader_ci +++ b/core/SConscript.bootloader_ci @@ -31,7 +31,7 @@ CPPDEFINES_HAL = [] SOURCE_HAL = [] PATH_HAL = [] -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL='Font_PixelOperator_Regular_8' FONT_DEMIBOLD=None FONT_BOLD=None diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu index 0723bf05b1..ccfb002580 100644 --- a/core/SConscript.bootloader_emu +++ b/core/SConscript.bootloader_emu @@ -33,7 +33,7 @@ CPPDEFINES_MOD = [] SOURCE_MOD = [] SOURCE_MOD_CRYPTO = [] -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL='Font_PixelOperator_Regular_8' FONT_DEMIBOLD='Font_PixelOperator_Regular_8' FONT_BOLD='Font_PixelOperator_Bold_8' @@ -271,7 +271,7 @@ RUST_LIBPATH = f'{RUST_LIBDIR}/lib{RUST_LIB}.a' def cargo_build(): if TREZOR_MODEL in ("1",): features = ["model_t1"] - elif TREZOR_MODEL in ("R",): + elif TREZOR_MODEL in ("R", "T3B1"): features = ["model_tr"] elif TREZOR_MODEL in ("T3T1",): features = ["model_mercury"] diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 127a63592d..22e0a591ea 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -42,7 +42,7 @@ PATH_HAL = [] FROZEN = True -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL='Font_PixelOperator_Regular_8' FONT_DEMIBOLD='Font_Unifont_Bold_16' FONT_BOLD='Font_PixelOperator_Bold_8' @@ -464,7 +464,7 @@ SOURCE_FIRMWARE = [ if TREZOR_MODEL in ('T', 'DISC1', 'DISC2'): UI_LAYOUT = 'UI_LAYOUT_TT' ui_layout_feature = 'model_tt' -elif TREZOR_MODEL in ('1', 'R'): +elif TREZOR_MODEL in ('1', 'R', 'T3B1'): UI_LAYOUT = 'UI_LAYOUT_TR' ui_layout_feature = 'model_tr' elif TREZOR_MODEL in ('T3T1',): diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index 4e32efdb69..8f5a5d62bc 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -34,7 +34,7 @@ CPPDEFINES_HAL = [] SOURCE_HAL = [] PATH_HAL = [] -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL=None FONT_DEMIBOLD=None FONT_BOLD='Font_PixelOperator_Bold_8' diff --git a/core/SConscript.reflash b/core/SConscript.reflash index a9d343542e..e40af8b1ef 100644 --- a/core/SConscript.reflash +++ b/core/SConscript.reflash @@ -29,7 +29,7 @@ CPPDEFINES_HAL = [] SOURCE_HAL = [] PATH_HAL = [] -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL=None FONT_DEMIBOLD=None FONT_BOLD='Font_PixelOperator_Bold_8' diff --git a/core/SConscript.unix b/core/SConscript.unix index 7d5d28869a..8dad6103b7 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -47,7 +47,7 @@ PYOPT = ARGUMENTS.get('PYOPT', '1') FROZEN = ARGUMENTS.get('TREZOR_EMULATOR_FROZEN', 0) RASPI = os.getenv('TREZOR_EMULATOR_RASPI') == '1' -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL='Font_PixelOperator_Regular_8' FONT_DEMIBOLD='Font_Unifont_Bold_16' FONT_BOLD='Font_PixelOperator_Bold_8' @@ -476,7 +476,7 @@ FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_ if TREZOR_MODEL in ('T',): UI_LAYOUT = 'UI_LAYOUT_TT' ui_layout_feature = 'model_tt' -elif TREZOR_MODEL in ('1', 'R'): +elif TREZOR_MODEL in ('1', 'R', 'T3B1'): UI_LAYOUT = 'UI_LAYOUT_TR' ui_layout_feature = 'model_tr' elif TREZOR_MODEL in ('T3T1',): diff --git a/core/embed/firmware/bootloaders/bootloader_T3B1_qa.bin b/core/embed/firmware/bootloaders/bootloader_T3B1_qa.bin new file mode 100755 index 0000000000000000000000000000000000000000..4a0444e88615fd5414398b06b2a1980aa15e4a33 GIT binary patch literal 93184 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 +#define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR1_I2C1RST + +#define OPTIGA_I2C_INSTANCE 0 +#define OPTIGA_RST_PORT GPIOE +#define OPTIGA_RST_PIN GPIO_PIN_13 +#define OPTIGA_RST_CLK_EN __HAL_RCC_GPIOE_CLK_ENABLE + +#endif //_TREZOR_T3B1_H diff --git a/core/embed/models/T3B1/model_T3B1.h b/core/embed/models/T3B1/model_T3B1.h new file mode 100644 index 0000000000..2f007c0d8a --- /dev/null +++ b/core/embed/models/T3B1/model_T3B1.h @@ -0,0 +1,50 @@ +#ifndef MODELS_MODEL_T3B1_H_ +#define MODELS_MODEL_T3B1_H_ + +#include "sizedefs.h" + +#define MODEL_NAME "Safe 3" +#define MODEL_FULL_NAME "Trezor Safe 3" +#define MODEL_INTERNAL_NAME "T3B1" +#define MODEL_INTERNAL_NAME_TOKEN T3B1 +#define MODEL_INTERNAL_NAME_QSTR MP_QSTR_T3B1 +#define MODEL_USB_MANUFACTURER "Trezor Company" +#define MODEL_USB_PRODUCT MODEL_FULL_NAME + +#define MODEL_BOARDLOADER_KEYS \ + (const uint8_t *)"\x76\xaf\x42\x6e\x61\x40\x6b\xad\x7c\x07\x7b\x40\x9c\x66\xfd\xe3\x9f\xb8\x17\x91\x93\x13\xae\x1e\x4c\x02\x53\x5c\x80\xbe\xed\x96", \ + (const uint8_t *)"\x61\x97\x51\xdc\x8d\x2d\x09\xd7\xe5\xdf\xb9\x9e\x41\xf6\x06\xde\xbd\xf4\x19\xf8\x5a\x81\x43\xe8\xe5\x39\x9e\xa6\x7a\x39\x88\xc7", \ + (const uint8_t *)"\xab\xf9\x4b\x66\x15\xa7\xdd\xe2\xa8\x71\xf7\xd6\x2c\x38\xef\xc7\xd9\xd8\xf6\x01\x0d\x88\x46\xbe\xe6\x36\xe4\xf3\xe6\x58\xa3\x8c", + +#define MODEL_BOOTLOADER_KEYS \ + (const uint8_t *)"\x33\x8b\x94\x9b\x7e\x3b\x26\x47\x0d\x4f\xe3\x69\x6f\xd6\xff\xf2\x87\x57\x26\x5d\x14\xcc\xa4\x8e\xbf\x2d\xb9\x7b\x4f\x5b\xc0\x39", \ + (const uint8_t *)"\x28\x68\x20\x27\x73\x0b\x78\x32\x01\xb0\x5a\x8c\x9d\x11\x68\x54\x47\xc1\x72\x97\xdb\x71\xb8\xa6\x0d\xc6\x93\xa4\x46\x10\x75\x1d", \ + (const uint8_t *)"\x9f\xbf\x31\xb4\xe3\x51\xa4\xcc\x81\xc7\x59\x95\xb2\x25\x7f\x0a\x71\x69\x26\x8d\xa5\xa4\x4e\x94\xb6\xa5\x59\x0d\x43\x4e\x32\xda", + +#define IMAGE_CHUNK_SIZE (128 * 1024) +#define IMAGE_HASH_SHA256 +#define BOARD_CAPABILITIES_ADDR 0x0C00FF00 + +// SHARED WITH MAKEFILE +#define FLASH_START 0x0C000000 +#define BOARDLOADER_START 0x0C004000 +#define BOOTLOADER_START 0x0C010000 +#define FIRMWARE_START 0x0C050000 +#define STORAGE_1_OFFSET 0x30000 +#define STORAGE_2_OFFSET 0x50000 +#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 BOARDLOADER_SECTOR_START 0x2 +#define BOARDLOADER_SECTOR_END 0x7 +#define BOOTLOADER_SECTOR_START 0x8 +#define BOOTLOADER_SECTOR_END 0x17 +#define FIRMWARE_SECTOR_START 0x28 +#define FIRMWARE_SECTOR_END 0xF7 +#define STORAGE_1_SECTOR_START 0x18 +#define STORAGE_1_SECTOR_END 0x1F +#define STORAGE_2_SECTOR_START 0x20 +#define STORAGE_2_SECTOR_END 0x27 + +#endif diff --git a/core/embed/models/T3B1/model_T3B1_layout.c b/core/embed/models/T3B1/model_T3B1_layout.c new file mode 100644 index 0000000000..3baae222ed --- /dev/null +++ b/core/embed/models/T3B1/model_T3B1_layout.c @@ -0,0 +1,96 @@ +#include "flash.h" +#include "model.h" + +const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT] = { + { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = STORAGE_1_SECTOR_START, + .num_sectors = + STORAGE_1_SECTOR_END - STORAGE_1_SECTOR_START + 1, + }, + }, + { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = STORAGE_2_SECTOR_START, + .num_sectors = + STORAGE_2_SECTOR_END - STORAGE_2_SECTOR_START + 1, + }, + }, +}; + +const flash_area_t BOARDLOADER_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = BOARDLOADER_SECTOR_START, + .num_sectors = + BOARDLOADER_SECTOR_END - BOARDLOADER_SECTOR_START + 1, + }, +}; + +const flash_area_t BOOTLOADER_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = BOOTLOADER_SECTOR_START, + .num_sectors = BOOTLOADER_SECTOR_END - BOOTLOADER_SECTOR_START + 1, + }, +}; + +const flash_area_t FIRMWARE_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = FIRMWARE_SECTOR_START, + .num_sectors = FIRMWARE_SECTOR_END - FIRMWARE_SECTOR_START + 1, + }, +}; + +const flash_area_t SECRET_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0, + .num_sectors = 2, + }, +}; + +const flash_area_t BHK_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 1, + .num_sectors = 1, + }, +}; + +const flash_area_t TRANSLATIONS_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 248, + .num_sectors = 8, + }, +}; + +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, + }, +}; diff --git a/core/embed/models/model.h b/core/embed/models/model.h index 69754ab5c1..fa797575b4 100644 --- a/core/embed/models/model.h +++ b/core/embed/models/model.h @@ -11,6 +11,8 @@ #include "T2B1/model_T2B1.h" #elif defined TREZOR_MODEL_T3T1 #include "T3T1/model_T3T1.h" +#elif defined TREZOR_MODEL_T3B1 +#include "T3B1/model_T3B1.h" #elif defined TREZOR_MODEL_DISC1 #include "D001/model_D001.h" #elif defined TREZOR_MODEL_DISC2 diff --git a/core/embed/trezorhal/stm32u5/button.c b/core/embed/trezorhal/stm32u5/button.c new file mode 120000 index 0000000000..9c6b0a7704 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/button.c @@ -0,0 +1 @@ +../stm32f4/button.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/consumption_mask.c b/core/embed/trezorhal/stm32u5/consumption_mask.c new file mode 100644 index 0000000000..859b430e91 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/consumption_mask.c @@ -0,0 +1,140 @@ +/* + * 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 "rng.h" + +#define SAMPLES 110 +#define TIMER_PERIOD 16640 // cca 10 KHz @ 160MHz + +uint32_t pwm_data[SAMPLES] = {0}; + +static DMA_NodeTypeDef Node1; +static DMA_QListTypeDef Queue; + +void consumption_mask_randomize() { + for (int i = 0; i < SAMPLES; i++) { + pwm_data[i] = rng_get() % TIMER_PERIOD; + } +} + +void consumption_mask_init(void) { + consumption_mask_randomize(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + GPIO_InitTypeDef GPIO_InitStructure = {0}; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_PULLUP; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Alternate = GPIO_AF1_TIM2; + GPIO_InitStructure.Pin = GPIO_PIN_5; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + + __HAL_RCC_TIM2_CLK_ENABLE(); + TIM_HandleTypeDef TIM2_Handle = {0}; + TIM2_Handle.State = HAL_TIM_STATE_RESET; + TIM2_Handle.Instance = TIM2; + TIM2_Handle.Init.Period = TIMER_PERIOD; + TIM2_Handle.Init.Prescaler = 0; + TIM2_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + TIM2_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; + TIM2_Handle.Init.RepetitionCounter = 0; + HAL_TIM_PWM_Init(&TIM2_Handle); + + TIM_OC_InitTypeDef TIM_OC_InitStructure = {0}; + TIM_OC_InitStructure.Pulse = 0; + TIM_OC_InitStructure.OCMode = TIM_OCMODE_PWM1; + TIM_OC_InitStructure.OCPolarity = TIM_OCPOLARITY_LOW; + TIM_OC_InitStructure.OCFastMode = TIM_OCFAST_DISABLE; + TIM_OC_InitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH; + TIM_OC_InitStructure.OCIdleState = TIM_OCIDLESTATE_SET; + TIM_OC_InitStructure.OCNIdleState = TIM_OCNIDLESTATE_SET; + HAL_TIM_PWM_ConfigChannel(&TIM2_Handle, &TIM_OC_InitStructure, TIM_CHANNEL_1); + + __HAL_RCC_GPDMA1_CLK_ENABLE(); + DMA_HandleTypeDef dma_handle = {0}; + + /* USER CODE END GPDMA1_Init 1 */ + dma_handle.Instance = GPDMA1_Channel1; + dma_handle.InitLinkedList.Priority = DMA_HIGH_PRIORITY; + dma_handle.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION; + dma_handle.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT1; + dma_handle.InitLinkedList.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER; + dma_handle.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR; + HAL_DMAEx_List_Init(&dma_handle); + + HAL_DMA_ConfigChannelAttributes(&dma_handle, DMA_CHANNEL_SEC | + DMA_CHANNEL_SRC_SEC | + DMA_CHANNEL_DEST_SEC); + + /* DMA node configuration declaration */ + DMA_NodeConfTypeDef pNodeConfig = {0}; + + /* Set node configuration ################################################*/ + pNodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE; + pNodeConfig.Init.Request = GPDMA1_REQUEST_TIM2_UP; + pNodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST; + pNodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH; + pNodeConfig.Init.SrcInc = DMA_SINC_INCREMENTED; + pNodeConfig.Init.DestInc = DMA_DINC_FIXED; + pNodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; + pNodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; + pNodeConfig.Init.SrcBurstLength = 1; + pNodeConfig.Init.DestBurstLength = 1; + pNodeConfig.Init.TransferAllocatedPort = + DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0; + pNodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; + pNodeConfig.RepeatBlockConfig.RepeatCount = 1; + pNodeConfig.RepeatBlockConfig.SrcAddrOffset = 0; + pNodeConfig.RepeatBlockConfig.DestAddrOffset = 0; + pNodeConfig.RepeatBlockConfig.BlkSrcAddrOffset = 0; + pNodeConfig.RepeatBlockConfig.BlkDestAddrOffset = 0; + pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED; + pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE; + pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED; + pNodeConfig.SrcAddress = (uint32_t)pwm_data; + pNodeConfig.DstAddress = (uint32_t)&TIM2->CCR1; + pNodeConfig.DataSize = SAMPLES * sizeof(uint32_t); + pNodeConfig.DestSecure = DMA_CHANNEL_DEST_SEC; + pNodeConfig.SrcSecure = DMA_CHANNEL_SRC_SEC; + + /* Build Node1 Node */ + HAL_DMAEx_List_BuildNode(&pNodeConfig, &Node1); + + /* Insert Node1 to Queue */ + HAL_DMAEx_List_InsertNode_Tail(&Queue, &Node1); + + HAL_DMAEx_List_SetCircularModeConfig(&Queue, &Node1); + HAL_DMAEx_List_SetCircularMode(&Queue); + + /* Link created queue to DMA channel #######################################*/ + HAL_DMAEx_List_LinkQ(&dma_handle, &Queue); + + TIM2->CR2 |= TIM_CR2_CCPC; // preloading CCR register + TIM2->CR2 |= TIM_CR2_CCUS; // preload when TRGI + TIM2->DIER |= TIM_DMA_UPDATE; // allow DMA request from update event + TIM2->CCR1 = 0; + + HAL_Delay(1); + + HAL_TIM_Base_Start(&TIM2_Handle); + HAL_TIM_PWM_Start(&TIM2_Handle, TIM_CHANNEL_1); + + HAL_DMAEx_List_Start(&dma_handle); +} diff --git a/core/embed/trezorhal/stm32u5/displays/vg-2864ksweg01.c b/core/embed/trezorhal/stm32u5/displays/vg-2864ksweg01.c new file mode 120000 index 0000000000..4a0a88bfeb --- /dev/null +++ b/core/embed/trezorhal/stm32u5/displays/vg-2864ksweg01.c @@ -0,0 +1 @@ +../../stm32f4/displays/vg-2864ksweg01.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/displays/vg-2864ksweg01.h b/core/embed/trezorhal/stm32u5/displays/vg-2864ksweg01.h new file mode 120000 index 0000000000..f57ce0f36c --- /dev/null +++ b/core/embed/trezorhal/stm32u5/displays/vg-2864ksweg01.h @@ -0,0 +1 @@ +../../stm32f4/displays/vg-2864ksweg01.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/platform.c b/core/embed/trezorhal/stm32u5/platform.c index f0127dc458..fd31a29e2b 100644 --- a/core/embed/trezorhal/stm32u5/platform.c +++ b/core/embed/trezorhal/stm32u5/platform.c @@ -176,6 +176,9 @@ void SystemInit(void) { ; #endif + // enable power supply for GPIOG 2 to 15 + PWR->SVMCR |= PWR_SVMCR_IO2SV; + __HAL_RCC_PWR_CLK_DISABLE(); // this will be overriden by static initialization diff --git a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h index 97c580fbb1..203b2245c2 100644 --- a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h +++ b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h @@ -80,7 +80,7 @@ extern "C" { /*#define HAL_MMC_MODULE_ENABLED */ /*#define HAL_SMARTCARD_MODULE_ENABLED */ /*#define HAL_SMBUS_MODULE_ENABLED */ -/*#define HAL_SPI_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED #define HAL_SRAM_MODULE_ENABLED #define HAL_TIM_MODULE_ENABLED /*#define HAL_TSC_MODULE_ENABLED */ diff --git a/core/embed/trezorhal/unix/flash.c b/core/embed/trezorhal/unix/flash.c index afee940183..6c3c9e48b0 100644 --- a/core/embed/trezorhal/unix/flash.c +++ b/core/embed/trezorhal/unix/flash.c @@ -39,7 +39,7 @@ #define FLASH_SECTOR_COUNT 24 #elif defined TREZOR_MODEL_1 #define FLASH_SECTOR_COUNT 12 -#elif defined TREZOR_MODEL_T3T1 +#elif defined TREZOR_MODEL_T3T1 || defined TREZOR_MODEL_T3B1 #define FLASH_SECTOR_COUNT 256 #else #error Unknown MCU @@ -86,7 +86,7 @@ static uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { [10] = 0x080C0000, // - 0x080DFFFF | 128 KiB [11] = 0x080E0000, // - 0x080FFFFF | 128 KiB [12] = 0x08100000, // last element - not a valid sector -#elif defined TREZOR_MODEL_T3T1 +#elif defined TREZOR_MODEL_T3T1 || defined TREZOR_MODEL_T3B1 [0] = 0x08000000, // - 0x08001FFF | 8 KiB // rest is initialized in flash_init #else @@ -105,7 +105,7 @@ static void flash_exit(void) { void flash_init(void) { if (FLASH_BUFFER) return; -#if defined TREZOR_MODEL_T3T1 +#if defined TREZOR_MODEL_T3T1 || defined TREZOR_MODEL_T3B1 for (size_t i = 0; i < FLASH_SECTOR_COUNT; i++) { FLASH_SECTOR_TABLE[i + 1] = FLASH_SECTOR_TABLE[i] + 0x2000; // 8KiB size sectors diff --git a/core/embed/vendorheader/T3B1/vendor_dev_DO_NOT_SIGN.json b/core/embed/vendorheader/T3B1/vendor_dev_DO_NOT_SIGN.json new file mode 100644 index 0000000000..7ded76ed4e --- /dev/null +++ b/core/embed/vendorheader/T3B1/vendor_dev_DO_NOT_SIGN.json @@ -0,0 +1,20 @@ +{ + "header_len": 512, + "text": "DEV ONLY, DO NOT USE!", + "hw_model": "T3B1", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "allow_run_with_secret": true, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "e28a8970753332bd72fef413e6b0b2ef1b4aadda7aa2c141f233712a6876b351", + "d4eec1869fb1b8a4e817516ad5a931557cb56805c3eb16e8f3a803d647df7869", + "772c8a442b7db06e166cfbc1ccbcbcde6f3eba76a4e98ef3ffc519502237d6ef" + ] +} diff --git a/core/embed/vendorheader/T3B1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/vendorheader/T3B1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin new file mode 100644 index 0000000000000000000000000000000000000000..2af057b5d0ea84448f5780bd942b037ef9c743f3 GIT binary patch literal 512 zcmWFuiV9<3Vt@iB=6c2uV<$rxpMl{~S7$+~vC-b5e_w>3ZP@f)+H38tsznDKKN%Nl zWt43Wyz=f~+x(3?mb?%T%(}YLFtlcC2J7M1VlO_gV7}&lzaq0-r^`jVc0-<6&hLX~ z_UyTrZ?~&#$;-aa|Bp%rD4Ab-FY4kNrr_`A6RD%%;;-Q6AEFQ%?5fDX5aRFYF2Nwd z;0km~a)N+}$e;i69tI4I9h{FEZpu66R7ynuQ|{qi(paAWF)mmG}EP6Rg< zR3D6E-e~VMM}fc4SR&zA)N u^A+CfwSISX8};73Zfst(g+((q%>QeTv`1lNLh$D&T4Ifc`ejld7&rk8Uw2*r literal 0 HcmV?d00001 diff --git a/core/embed/vendorheader/T3B1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin b/core/embed/vendorheader/T3B1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin new file mode 100644 index 0000000000000000000000000000000000000000..21c4b380e57c064f0e134732f3f0b39a54a4c464 GIT binary patch literal 512 zcmWFuiV9<3Vt@iB=6c2uV<$rxpMl{~S7$+~vC-b5e_w>3ZP@f)+H38tsznDKKN%Nl zWt43Wyz=f~+x(3?mb?%T%(}YLFtlcC2J7M1VlO_gV7}&lzaq0-r^`jVc0-<6&hLX~ z_UyTrZ?~&#$;-aa|Bp%rD4Ab-FY4kNrr_`A6RD%%;;-Q6AEFQ%?5fDX5aRFYF2Nwd z;0km~a)N+}$e;i69tI4I9h{FEZpu66R7ynuQ|{qi(paAWF)mmG}EP6Rg< hR3D6E-e~VMM}fc4SR&z list[str]: + + features_available: list[str] = [] + board = "T3B1/boards/t3b1-unix.h" + hw_model = get_hw_model_as_number("T3B1") + hw_revision = 0 + mcu = "STM32U585xx" + + if "new_rendering" in features_wanted: + defines += ["XFRAMEBUFFER", "DISPLAY_MONO"] + features_available.append("xframebuffer") + features_available.append("display_mono") + + defines += [mcu] + defines += [f'TREZOR_BOARD=\\"{board}\\"'] + defines += [f"HW_MODEL={hw_model}"] + defines += [f"HW_REVISION={hw_revision}"] + defines += [f"MCU_TYPE={mcu}"] + defines += ["FLASH_BIT_ACCESS=1"] + defines += ["FLASH_BLOCK_WORDS=1"] + + if "sbu" in features_wanted: + sources += ["embed/trezorhal/unix/sbu.c"] + + if "optiga_hal" in features_wanted: + sources += ["embed/trezorhal/unix/optiga_hal.c"] + + if "optiga" in features_wanted: + sources += ["embed/trezorhal/unix/optiga.c"] + features_available.append("optiga") + + if "input" in features_wanted: + sources += ["embed/trezorhal/unix/button.c"] + features_available.append("button") + + sources += ["embed/models/T3B1/model_T3B1_layout.c"] + + return features_available diff --git a/core/site_scons/models/T3B1/trezor_t3b1_revB.py b/core/site_scons/models/T3B1/trezor_t3b1_revB.py new file mode 100644 index 0000000000..9682dd3576 --- /dev/null +++ b/core/site_scons/models/T3B1/trezor_t3b1_revB.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from .. import get_hw_model_as_number +from ..stm32u5_common import stm32u5_common_files + + +def configure( + env: dict, + features_wanted: list[str], + defines: list[str | tuple[str, str]], + sources: list[str], + paths: list[str], +) -> list[str]: + features_available: list[str] = [] + board = "T3B1/boards/trezor_t3b1_revB.h" + display = "vg-2864ksweg01.c" + hw_model = get_hw_model_as_number("T3B1") + hw_revision = "B" + + mcu = "STM32U585xx" + linker_script = "stm32u58" + + stm32u5_common_files(env, defines, sources, paths) + + env.get("ENV")[ + "CPU_ASFLAGS" + ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 " + env.get("ENV")[ + "CPU_CCFLAGS" + ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 -mcmse " + env.get("ENV")["RUST_TARGET"] = "thumbv8m.main-none-eabihf" + + defines += [mcu] + defines += [f'TREZOR_BOARD=\\"{board}\\"'] + defines += [f"HW_MODEL={hw_model}"] + defines += [f"HW_REVISION={ord(hw_revision)}"] + sources += [ + "embed/models/T3B1/model_T3B1_layout.c", + ] + sources += [f"embed/trezorhal/stm32u5/displays/{display}"] + + if "input" in features_wanted: + sources += ["embed/trezorhal/stm32u5/button.c"] + features_available.append("button") + + if "sbu" in features_wanted: + sources += ["embed/trezorhal/stm32u5/sbu.c"] + features_available.append("sbu") + + if "usb" in features_wanted: + sources += [ + "embed/trezorhal/stm32u5/usb/usb_class_hid.c", + "embed/trezorhal/stm32u5/usb/usb_class_vcp.c", + "embed/trezorhal/stm32u5/usb/usb_class_webusb.c", + "embed/trezorhal/stm32u5/usb/usb.c", + "embed/trezorhal/stm32u5/usb/usbd_conf.c", + "embed/trezorhal/stm32u5/usb/usbd_core.c", + "embed/trezorhal/stm32u5/usb/usbd_ctlreq.c", + "embed/trezorhal/stm32u5/usb/usbd_ioreq.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_ll_usb.c", + ] + features_available.append("usb") + + if "optiga" in features_wanted: + defines += ["USE_OPTIGA=1"] + sources += ["embed/trezorhal/stm32u5/i2c.c"] + sources += ["embed/trezorhal/stm32u5/optiga_hal.c"] + sources += ["embed/trezorhal/optiga/optiga.c"] + sources += ["embed/trezorhal/optiga/optiga_commands.c"] + sources += ["embed/trezorhal/optiga/optiga_transport.c"] + sources += ["vendor/trezor-crypto/hash_to_curve.c"] + features_available.append("optiga") + + if "consumption_mask" in features_wanted: + sources += ["embed/trezorhal/stm32u5/consumption_mask.c"] + sources += ["vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_tim.c"] + + env.get("ENV")["TREZOR_BOARD"] = board + env.get("ENV")["MCU_TYPE"] = mcu + env.get("ENV")["LINKER_SCRIPT"] = linker_script + + defs = env.get("CPPDEFINES_IMPLICIT") + defs += ["__ARM_FEATURE_CMSE=3"] + + return features_available diff --git a/core/site_scons/models/__init__.py b/core/site_scons/models/__init__.py index 1703168f67..f290cfffbb 100644 --- a/core/site_scons/models/__init__.py +++ b/core/site_scons/models/__init__.py @@ -32,9 +32,11 @@ def get_model_identifier(model: str) -> str: return "T2B1" elif model == "T3T1": return "T3T1" + elif model == "T3B1": + return "T3B1" elif model == "DISC1": return "D001" elif model == "DISC2": return "D002" else: - raise Exception("Unknown model") + return model diff --git a/python/.changelog.d/3728.added b/python/.changelog.d/3728.added new file mode 100644 index 0000000000..5f87842afa --- /dev/null +++ b/python/.changelog.d/3728.added @@ -0,0 +1 @@ +Added support for T3B1 diff --git a/python/src/trezorlib/firmware/models.py b/python/src/trezorlib/firmware/models.py index 1bc8a900e4..ecab10536a 100644 --- a/python/src/trezorlib/firmware/models.py +++ b/python/src/trezorlib/firmware/models.py @@ -31,6 +31,7 @@ class Model(Enum): T1B1 = b"T1B1" T2T1 = b"T2T1" T3T1 = b"T3T1" + T3B1 = b"T3B1" T2B1 = b"T2B1" D001 = b"D001" D002 = b"D002" @@ -246,6 +247,30 @@ T3T1 = ModelKeys( firmware_sigs_needed=-1, ) +T3B1 = ModelKeys( + production=False, + boardloader_keys=[ + bytes.fromhex(key) + for key in ( + "db995fe25169d141cab9bbba92baa01f9f2e1ece7df4cb2ac05190f37fcc1f9d", + "2152f8d19b791d24453242e15f2eab6cb7cffa7b6a5ed30097960e069881db12", + "22fc297792f0b6ffc0bfcfdb7edb0c0aa14e025a365ec0e342e86e3829cb74b6", + ) + ], + boardloader_sigs_needed=2, + bootloader_keys=[ + bytes.fromhex(key) + for key in ( + "d759793bbc13a2819a827c76adb6fba8a49aee007f49f2d0992d99b825ad2c48", + "6355691c178a8ff91007a7478afb955ef7352c63e7b25703984cf78b26e21a56", + "ee93a4f66f8d16b819bb9beb9ffccdfcdc1412e87fee6a324c2a99a1e0e67148", + ) + ], + bootloader_sigs_needed=2, + firmware_keys=(), + firmware_sigs_needed=-1, +) + LEGACY_HASH_PARAMS = FirmwareHashParameters( hash_function=hashlib.sha256, chunk_size=1024 * 64, @@ -264,6 +289,12 @@ T3T1_HASH_PARAMS = FirmwareHashParameters( padding_byte=None, ) +T3B1_HASH_PARAMS = FirmwareHashParameters( + hash_function=hashlib.sha256, + chunk_size=1024 * 128, + padding_byte=None, +) + D002_HASH_PARAMS = FirmwareHashParameters( hash_function=hashlib.sha256, chunk_size=1024 * 256, @@ -275,6 +306,7 @@ MODEL_MAP = { Model.T2T1: T2T1, Model.T2B1: T2B1, Model.T3T1: T3T1, + Model.T3B1: T3B1, Model.D001: TREZOR_CORE_DEV, Model.D002: TREZOR_CORE_DEV, } @@ -284,6 +316,7 @@ MODEL_MAP_DEV = { Model.T2T1: TREZOR_CORE_DEV, Model.T2B1: TREZOR_CORE_DEV, Model.T3T1: TREZOR_CORE_DEV, + Model.T3B1: TREZOR_CORE_DEV, Model.D001: TREZOR_CORE_DEV, Model.D002: TREZOR_CORE_DEV, } @@ -293,6 +326,7 @@ MODEL_HASH_PARAMS_MAP = { Model.T2T1: T2T1_HASH_PARAMS, Model.T2B1: T2T1_HASH_PARAMS, Model.T3T1: T3T1_HASH_PARAMS, + Model.T3B1: T3B1_HASH_PARAMS, Model.D001: T2T1_HASH_PARAMS, Model.D002: D002_HASH_PARAMS, } @@ -307,6 +341,7 @@ TREZOR_ONE_V3_DEV = LEGACY_V3_DEV TREZOR_T = T2T1 TREZOR_R = T2B1 TREZOR_T3T1 = T3T1 +TREZOR_T3B1 = T3B1 TREZOR_T_DEV = TREZOR_CORE_DEV TREZOR_R_DEV = TREZOR_CORE_DEV diff --git a/python/src/trezorlib/models.py b/python/src/trezorlib/models.py index 3e1f7261a0..2fde03eb2d 100644 --- a/python/src/trezorlib/models.py +++ b/python/src/trezorlib/models.py @@ -72,6 +72,15 @@ T3T1 = TrezorModel( default_mapping=mapping.DEFAULT_MAPPING, ) +T3B1 = TrezorModel( + name="Safe 3", + internal_name="T3B1", + minimum_version=(2, 1, 0), + vendors=VENDORS, + usb_ids=((0x1209, 0x53C1), (0x1209, 0x53C0)), + default_mapping=mapping.DEFAULT_MAPPING, +) + DISC1 = TrezorModel( name="DISC1", internal_name="D001", @@ -100,7 +109,7 @@ TREZOR_SAFE5 = T3T1 TREZOR_DISC1 = DISC1 TREZOR_DISC2 = DISC2 -TREZORS = {T1B1, T2T1, T2B1, T3T1, DISC1, DISC2} +TREZORS = {T1B1, T2T1, T2B1, T3T1, T3B1, DISC1, DISC2} def by_name(name: Optional[str]) -> Optional[TrezorModel]: