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 0000000000..4a0444e886 Binary files /dev/null and b/core/embed/firmware/bootloaders/bootloader_T3B1_qa.bin differ diff --git a/core/embed/firmware/memory_T3B1.ld b/core/embed/firmware/memory_T3B1.ld new file mode 120000 index 0000000000..b5bfd3715e --- /dev/null +++ b/core/embed/firmware/memory_T3B1.ld @@ -0,0 +1 @@ +memory_T3T1.ld \ No newline at end of file diff --git a/core/embed/models/T3B1/boards/t3b1-unix.h b/core/embed/models/T3B1/boards/t3b1-unix.h new file mode 100644 index 0000000000..ee0871d40c --- /dev/null +++ b/core/embed/models/T3B1/boards/t3b1-unix.h @@ -0,0 +1,24 @@ +#ifndef BOARDS_T3B1_UNIX_H +#define BOARDS_T3B1_UNIX_H + +#define USE_BUTTON 1 +#define USE_SBU 1 +#define USE_OPTIGA 1 + +#define MAX_DISPLAY_RESX 128 +#define MAX_DISPLAY_RESY 64 +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 +#define TREZOR_FONT_BPP 1 + +#define WINDOW_WIDTH 193 +#define WINDOW_HEIGHT 339 +#define TOUCH_OFFSET_X 32 +#define TOUCH_OFFSET_Y 84 + +#define ORIENTATION_NS 1 + +#define BACKGROUND_FILE "T2B1/background_T2B1.h" +#define BACKGROUND_NAME background_T2B1_png + +#endif // BOARDS_T2B1_UNIX_H diff --git a/core/embed/models/T3B1/boards/trezor_t3b1_revB.h b/core/embed/models/T3B1/boards/trezor_t3b1_revB.h new file mode 100644 index 0000000000..e91a2952d2 --- /dev/null +++ b/core/embed/models/T3B1/boards/trezor_t3b1_revB.h @@ -0,0 +1,63 @@ +#ifndef _TREZOR_T3B1_H +#define _TREZOR_T3B1_H + +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 + +#define VDD_3V3 1 + +#define USE_I2C 1 +#define USE_BUTTON 1 +#define USE_SBU 1 +#define USE_HASH_PROCESSOR 1 +#define USE_CONSUMPTION_MASK 1 + +#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h" + +#define BTN_LEFT_PIN GPIO_PIN_11 +#define BTN_LEFT_PORT GPIOC +#define BTN_LEFT_CLK_ENA __HAL_RCC_GPIOC_CLK_ENABLE +#define BTN_RIGHT_PIN GPIO_PIN_10 +#define BTN_RIGHT_PORT GPIOD +#define BTN_RIGHT_CLK_ENA __HAL_RCC_GPIOD_CLK_ENABLE + +#define OLED_DC_PORT GPIOC +#define OLED_DC_PIN GPIO_PIN_8 // Data/Command +#define OLED_DC_CLK_ENA __HAL_RCC_GPIOC_CLK_ENABLE +#define OLED_CS_PORT GPIOG +#define OLED_CS_PIN GPIO_PIN_5 // SPI Select +#define OLED_CS_CLK_ENA __HAL_RCC_GPIOG_CLK_ENABLE +#define OLED_RST_PORT GPIOG +#define OLED_RST_PIN GPIO_PIN_8 // Reset display +#define OLED_RST_CLK_ENA __HAL_RCC_GPIOG_CLK_ENABLE + +#define OLED_SPI SPI1 +#define OLED_SPI_AF GPIO_AF5_SPI1 +#define OLED_SPI_CLK_ENA __HAL_RCC_SPI1_CLK_ENABLE +#define OLED_SPI_SCK_PORT GPIOG +#define OLED_SPI_SCK_PIN GPIO_PIN_2 // SPI SCK +#define OLED_SPI_SCK_CLK_ENA __HAL_RCC_GPIOG_CLK_ENABLE +#define OLED_SPI_MOSI_PORT GPIOG +#define OLED_SPI_MOSI_PIN GPIO_PIN_4 // SPI MOSI +#define OLED_SPI_MOSI_CLK_ENA __HAL_RCC_GPIOG_CLK_ENABLE + +#define I2C_COUNT 1 +#define I2C_INSTANCE_0 I2C1 +#define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C1_CLK_ENABLE +#define I2C_INSTANCE_0_CLK_DIS __HAL_RCC_I2C1_CLK_DISABLE +#define I2C_INSTANCE_0_PIN_AF GPIO_AF4_I2C1 +#define I2C_INSTANCE_0_SDA_PORT GPIOG +#define I2C_INSTANCE_0_SDA_PIN GPIO_PIN_13 +#define I2C_INSTANCE_0_SDA_CLK_EN __HAL_RCC_GPIOG_CLK_ENABLE +#define I2C_INSTANCE_0_SCL_PORT GPIOG +#define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_14 +#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 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 0000000000..2af057b5d0 Binary files /dev/null and b/core/embed/vendorheader/T3B1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin differ 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 0000000000..21c4b380e5 Binary files /dev/null and b/core/embed/vendorheader/T3B1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin differ diff --git a/core/embed/vendorheader/generate.sh b/core/embed/vendorheader/generate.sh index 2a63dc8ef5..a2f115d8de 100755 --- a/core/embed/vendorheader/generate.sh +++ b/core/embed/vendorheader/generate.sh @@ -16,7 +16,7 @@ for arg in "$@"; do fi done -MODELS=(T2T1 T2B1 T3T1 D001 D002) +MODELS=(T2T1 T2B1 T3T1 T3B1 D001 D002) for MODEL in ${MODELS[@]}; do cd $MODEL diff --git a/core/site_scons/models/T3B1/__init__.py b/core/site_scons/models/T3B1/__init__.py new file mode 100644 index 0000000000..4231282a88 --- /dev/null +++ b/core/site_scons/models/T3B1/__init__.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +from typing import Optional + +from . import emulator, trezor_t3b1_revB + + +def configure_board( + revision: Optional[int | str], + features_wanted: list[str], + env: dict, # type: ignore + defines: list[str | tuple[str, str]], + sources: list[str], + paths: list[str], +): + # Set default revision if None + revision = revision or "B" + + # Mapping of revisions to their respective configurations + revision_map = { + "emulator": emulator, + "B": trezor_t3b1_revB, + } + + module = revision_map.get(revision) + + if module: + return module.configure(env, features_wanted, defines, sources, paths) + + raise Exception("Unknown T3B1 revision") diff --git a/core/site_scons/models/T3B1/emulator.py b/core/site_scons/models/T3B1/emulator.py new file mode 100644 index 0000000000..4d8d8d3b0c --- /dev/null +++ b/core/site_scons/models/T3B1/emulator.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +from .. import get_hw_model_as_number + + +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/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]: