diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index a76088afeb..92ae8fba37 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -87,6 +87,7 @@ if PRODUCTION_MODEL == 'H': 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dcmi.c', 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma.c', 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma_ex.c', + 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_exti.c', 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash.c', 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash_ex.c', 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c', @@ -223,6 +224,7 @@ SOURCE_TREZORHAL = [ 'embed/trezorhal/camera.c', 'embed/trezorhal/gt911.c', 'embed/trezorhal/sdram.c', + 'embed/trezorhal/stm32_it_handler.c', ] diff --git a/core/SConscript.firmware b/core/SConscript.firmware index b35a4c00d5..42b7aaec68 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -409,6 +409,7 @@ if PRODUCTION_MODEL == 'H': 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dcmi.c', 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma.c', 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma_ex.c', + 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_exti.c', 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash.c', 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash_ex.c', 'vendor/micropython/lib/stm32lib/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c', diff --git a/core/embed/bootloader/memory.ld b/core/embed/bootloader/memory.ld index 5e26de23e9..07d642162b 100644 --- a/core/embed/bootloader/memory.ld +++ b/core/embed/bootloader/memory.ld @@ -6,6 +6,8 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 256K AXIRAM (wal) : ORIGIN = 0x24000000, LENGTH = 512K SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 128K + /* SRAM3 is used for DMA */ + SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 32K } main_stack_base = ORIGIN(SRAM) + LENGTH(SRAM); /* 8-byte aligned full descending stack */ @@ -55,6 +57,11 @@ SECTIONS { . = 4K; /* this acts as a build time assertion that at least this much memory is available for stack use */ } >SRAM + .sram3 : ALIGN(4) { + *(.sram3*); + . = ALIGN(4); + } >SRAM3 + /* this is needed, otherwise will have "undefined reference to `end'" error */ .heap : ALIGN(4) { PROVIDE ( end = . ); diff --git a/core/embed/extmod/modtrezorio/modtrezorio-poll.h b/core/embed/extmod/modtrezorio/modtrezorio-poll.h index 85d210e62e..630ed2b5b0 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio-poll.h +++ b/core/embed/extmod/modtrezorio/modtrezorio-poll.h @@ -27,7 +27,6 @@ #include "spi_legacy.h" #include "usart.h" -#define SPI_IFACE (6) #define FINGERPRINT_IFACE (7) #define USB_DATA_IFACE (253) #define BUTTON_IFACE (254) @@ -37,8 +36,9 @@ #define UART_IFACE (127) #define USB_STATE_IFACE (128) #define LOCAL_IFACE (99) +#define SPI_IFACE (100) +#define SPI_FIDO_IFACE (101) -extern bool usb_connected_previously; extern bool local_interface_ready; /// package: trezorio.__init__ @@ -90,72 +90,7 @@ STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref, #endif if (false) { - } -#if defined TREZOR_MODEL_T - else if (iface == TOUCH_IFACE) { - const uint32_t evt = touch_read(); - if (evt) { - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); - const uint32_t etype = (evt >> 24) & 0xFFU; // event type - const uint32_t ex = (evt >> 12) & 0xFFFU; // x position - const uint32_t ey = evt & 0xFFFU; // y position - uint32_t exr; // rotated x position - uint32_t eyr; // rotated y position - switch (display_orientation(-1)) { - case 90: - exr = ey; - eyr = DISPLAY_RESX - ex; - break; - case 180: - exr = DISPLAY_RESX - ex; - eyr = DISPLAY_RESY - ey; - break; - case 270: - exr = DISPLAY_RESY - ey; - eyr = ex; - break; - default: - exr = ex; - eyr = ey; - break; - } - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(etype); - tuple->items[1] = MP_OBJ_NEW_SMALL_INT(exr); - tuple->items[2] = MP_OBJ_NEW_SMALL_INT(eyr); - ret->items[0] = MP_OBJ_NEW_SMALL_INT(i); - ret->items[1] = MP_OBJ_FROM_PTR(tuple); - return mp_const_true; - } - } else if (iface == USB_DATA_IFACE) { - bool usb_connected = usb_configured() == sectrue ? true : false; - if (usb_connected != usb_connected_previously) { - usb_connected_previously = usb_connected; - ret->items[0] = MP_OBJ_NEW_SMALL_INT(i); - ret->items[1] = usb_connected ? mp_const_true : mp_const_false; - return mp_const_true; - } - } -#elif defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R - else if (iface == BUTTON_IFACE) { - const uint32_t evt = button_read(); - if (evt & (BTN_EVT_DOWN | BTN_EVT_UP)) { - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); - uint32_t etype = (evt >> 24) & 0x3U; // button down/up - uint32_t en = evt & 0xFFFF; // button number - if (display_orientation(-1) == 180) { - en = (en == BTN_LEFT) ? BTN_RIGHT : BTN_LEFT; - } - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(etype); - tuple->items[1] = MP_OBJ_NEW_SMALL_INT(en); - ret->items[0] = MP_OBJ_NEW_SMALL_INT(i); - ret->items[1] = MP_OBJ_FROM_PTR(tuple); - return mp_const_true; - } - } -#else -#error Unknown Trezor model -#endif - else if (iface == USB_STATE_IFACE) { + } else if (iface == USB_STATE_IFACE) { static bool usb_connect = false, usb_connect_bak = false; static bool usb_open = false, usb_open_bak = false; static int counter0 = 0, counter1 = 0; @@ -237,8 +172,7 @@ STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref, local_interface_ready = false; return mp_const_true; } - } // TODO:FIX IT - else if (iface == SPI_IFACE) { + } else if (iface == SPI_IFACE) { uint8_t buf[64] = {0}; int len = spi_slave_poll(buf); if (len > 0) { @@ -246,6 +180,14 @@ STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref, ret->items[1] = mp_obj_new_bytes(buf, len); return mp_const_true; } + } else if (iface == SPI_FIDO_IFACE) { + uint8_t buf[1024] = {0}; + int len = spi_slave_poll_fido(buf); + if (len > 0) { + ret->items[0] = MP_OBJ_NEW_SMALL_INT(i); + ret->items[1] = mp_obj_new_bytes(buf, len); + return mp_const_true; + } } } else if (mode == POLL_WRITE) { int res = usb_webusb_can_write(iface); @@ -261,7 +203,7 @@ STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref, ret->items[0] = MP_OBJ_NEW_SMALL_INT(i); ret->items[1] = mp_const_false; return mp_const_true; - } else if (iface == SPI_IFACE) { + } else if (iface == SPI_IFACE || iface == SPI_FIDO_IFACE) { if (sectrue == spi_can_write()) { ret->items[0] = MP_OBJ_NEW_SMALL_INT(i); ret->items[1] = mp_const_true; diff --git a/core/embed/extmod/modtrezorio/modtrezorio-spi.h b/core/embed/extmod/modtrezorio/modtrezorio-spi.h index 7063ebaa80..4f6a7fff84 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio-spi.h +++ b/core/embed/extmod/modtrezorio/modtrezorio-spi.h @@ -68,7 +68,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_SPI_iface_num_obj, STATIC mp_obj_t mod_trezorio_SPI_write(mp_obj_t self, mp_obj_t msg) { mp_buffer_info_t buf = {0}; mp_get_buffer_raise(msg, &buf, MP_BUFFER_READ); - ssize_t r = spi_slave_send(buf.buf, buf.len, 100); + ssize_t r = spi_slave_send(buf.buf, buf.len, 500); return MP_OBJ_NEW_SMALL_INT(r); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_SPI_write_obj, diff --git a/core/embed/extmod/modtrezorio/modtrezorio.c b/core/embed/extmod/modtrezorio/modtrezorio.c index cc8d54751b..078d62367e 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio.c +++ b/core/embed/extmod/modtrezorio/modtrezorio.c @@ -31,9 +31,6 @@ #include "touch.h" #include "usb.h" -// Whether USB data pins were connected on last check (USB configured) -bool usb_connected_previously = true; - bool local_interface_ready = false; #define CHECK_PARAM_RANGE(value, minimum, maximum) \ @@ -83,6 +80,9 @@ bool local_interface_ready = false; /// BUTTON_LEFT: int # button number of left button /// BUTTON_RIGHT: int # button number of right button +/// SPI_FACE: int # interface id of the spi events +/// SPI_FIDO_FACE: int # interface id of the spi fido events + /// WireInterface = Union[HID, WebUSB, SPI] /// USB_CHECK: int # interface id for check of USB data connection /// FINGERPRINT_STATE: int # interface id of the fingerprint state events @@ -134,6 +134,9 @@ STATIC const mp_rom_map_elem_t mp_module_trezorio_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_LOCAL_CTL), MP_ROM_PTR(&mod_trezorio_LOCAL_CTL_type)}, {MP_ROM_QSTR(MP_QSTR_USB_CHECK), MP_ROM_INT(USB_DATA_IFACE)}, + + {MP_ROM_QSTR(MP_QSTR_SPI_FACE), MP_ROM_INT(SPI_IFACE)}, + {MP_ROM_QSTR(MP_QSTR_SPI_FIDO_FACE), MP_ROM_INT(SPI_FIDO_IFACE)}, }; STATIC MP_DEFINE_CONST_DICT(mp_module_trezorio_globals, diff --git a/core/embed/firmware/memory_H.ld b/core/embed/firmware/memory_H.ld index 2d4513791c..e16ce27fca 100644 --- a/core/embed/firmware/memory_H.ld +++ b/core/embed/firmware/memory_H.ld @@ -9,6 +9,8 @@ MEMORY { SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 128K SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 128K SRAM2 (wal) : ORIGIN = 0x30020000, LENGTH = 128K + /* SRAM3 is used for DMA */ + SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 32K EXRAM (wal) : ORIGIN = 0xD1C00000, LENGTH = 2048K } @@ -80,6 +82,11 @@ SECTIONS { *(sram1) } >SRAM1 + .sram3 : ALIGN(4) { + *(.sram3*); + . = ALIGN(4); + } >SRAM3 + .bss2 : ALIGN(4) { *(.bss.global_image); *(.bss.global_feature); diff --git a/core/embed/fp_sensor_wrapper/fpsensor_platform.c b/core/embed/fp_sensor_wrapper/fpsensor_platform.c index e92a2b775e..113a2e5cbf 100644 --- a/core/embed/fp_sensor_wrapper/fpsensor_platform.c +++ b/core/embed/fp_sensor_wrapper/fpsensor_platform.c @@ -56,11 +56,6 @@ uint8_t fpsensor_gpio_init() return FPSENSOR_OK; } -void EXTI15_10_IRQHandler(void) -{ - HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15); -} - void fpsensor_state_set(bool state) { fp_touched = state; diff --git a/core/embed/trezorhal/gt911.c b/core/embed/trezorhal/gt911.c index 2289bb3a7e..ca286613ba 100644 --- a/core/embed/trezorhal/gt911.c +++ b/core/embed/trezorhal/gt911.c @@ -129,8 +129,6 @@ void gt911_enable_irq(void) { void gt911_disable_irq(void) { HAL_NVIC_DisableIRQ(EXTI2_IRQn); } -void EXTI2_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2); } - void gt911_test(void) { while (1) { gt911_read_location(); diff --git a/core/embed/trezorhal/spi_legacy.c b/core/embed/trezorhal/spi_legacy.c index 42af12e03e..dff80bbd57 100644 --- a/core/embed/trezorhal/spi_legacy.c +++ b/core/embed/trezorhal/spi_legacy.c @@ -12,16 +12,33 @@ SPI_HandleTypeDef spi; static DMA_HandleTypeDef hdma_tx; static DMA_HandleTypeDef hdma_rx; -static uint8_t* recv_buf = (uint8_t*)0x30040000; -static uint8_t* send_buf = (uint8_t*)0x30040040; +// SRAM3 32K +static uint8_t dma_recv_buf[SPI_BUF_MAX_IN_LEN] __attribute__((section(".sram3"))); +static uint8_t dma_send_buf[SPI_BUF_MAX_OUT_LEN] __attribute__((section(".sram3"))); + static volatile int32_t spi_rx_event = 0; static volatile int32_t spi_tx_event = 0; static volatile int32_t spi_abort_event = 0; +static volatile bool spi_data_dir_in = true; +static volatile bool spi_data_received = false; ChannelType host_channel = CHANNEL_NULL; uint8_t spi_data_in[SPI_BUF_MAX_IN_LEN]; uint8_t spi_data_out[SPI_BUF_MAX_OUT_LEN]; +#define DATA_HEADER_SIZE 3 +#define DATA_FIDO_HEADER_SIZE 3 + +typedef enum +{ + SPI_STATE_IDLE, + SPI_STATE_FIDO_HEADER, + SPI_STATE_FIDO_DATA, + SPI_STATE_ABORTED, +} SPI_State; + +SPI_State spi_state = SPI_STATE_IDLE; + trans_fifo spi_fifo_in = { .p_buf = spi_data_in, .buf_size = SPI_BUF_MAX_IN_LEN, @@ -60,6 +77,7 @@ int32_t wait_spi_tx_event(int32_t timeout) { if ( (HAL_GetTick() - tickstart) > timeout ) { + spi_tx_event = 0; return -1; } } @@ -68,18 +86,18 @@ int32_t wait_spi_tx_event(int32_t timeout) void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef* hspi) { - SET_RX_BUS_BUSY(); + ST_BLE_STATUS_IO_BUSY(); if ( spi_rx_event ) { spi_rx_event = 0; } - if ( !fifo_write_no_overflow(&spi_fifo_in, recv_buf, hspi->RxXferSize) ) + if ( !fifo_write_no_overflow(&spi_fifo_in, dma_recv_buf, hspi->RxXferSize) ) { - memset(recv_buf, 0, SPI_PKG_SIZE); + memset(dma_recv_buf, 0, hspi->RxXferSize); } - HAL_SPI_Receive_DMA(&spi, recv_buf, SPI_PKG_SIZE); - SET_RX_BUS_IDEL(); + HAL_SPI_Receive_DMA(&spi, dma_recv_buf, sizeof(dma_recv_buf)); + ST_BLE_STATUS_IO_IDLE(); } void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef* hspi) @@ -89,7 +107,7 @@ void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef* hspi) spi_tx_event = 0; } - HAL_SPI_Receive_DMA(&spi, recv_buf, SPI_PKG_SIZE); + HAL_SPI_Receive_DMA(&spi, dma_recv_buf, sizeof(dma_recv_buf)); } void HAL_SPI_ErrorCallback(SPI_HandleTypeDef* hspi) @@ -111,8 +129,6 @@ int32_t spi_slave_init() { GPIO_InitTypeDef gpio; - __HAL_RCC_DMA1_FORCE_RESET(); - __HAL_RCC_DMA1_RELEASE_RESET(); __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_RCC_SPI2_FORCE_RESET(); @@ -172,7 +188,7 @@ int32_t spi_slave_init() /* Configure the DMA handler for Transmission process */ hdma_tx.Instance = SPIx_TX_DMA_STREAM; hdma_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; - hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; hdma_tx.Init.MemBurst = DMA_MBURST_SINGLE; hdma_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; hdma_tx.Init.Request = SPIx_TX_DMA_REQUEST; @@ -193,7 +209,7 @@ int32_t spi_slave_init() hdma_rx.Instance = SPIx_RX_DMA_STREAM; hdma_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; - hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; hdma_rx.Init.MemBurst = DMA_MBURST_SINGLE; hdma_rx.Init.PeriphBurst = DMA_PBURST_SINGLE; hdma_rx.Init.Request = SPIx_RX_DMA_REQUEST; @@ -222,11 +238,24 @@ int32_t spi_slave_init() NVIC_SetPriority(SPI2_IRQn, IRQ_PRI_SPI); HAL_NVIC_EnableIRQ(SPI2_IRQn); - memset(recv_buf, 0, SPI_PKG_SIZE); + EXTI_HandleTypeDef hexti = {0}; + + EXTI_ConfigTypeDef pExtiConfig; + pExtiConfig.Line = EXTI_LINE_11; + pExtiConfig.Mode = EXTI_MODE_INTERRUPT; + pExtiConfig.Trigger = EXTI_TRIGGER_RISING; + pExtiConfig.GPIOSel = EXTI_GPIOA; + + HAL_EXTI_SetConfigLine(&hexti, &pExtiConfig); + + NVIC_SetPriority(EXTI15_10_IRQn, IRQ_PRI_GPIO); + HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); + + memset(dma_recv_buf, 0, sizeof(dma_recv_buf)); spi_rx_event = 1; - SET_RX_BUS_IDEL(); + ST_BLE_STATUS_IO_IDLE(); /* start SPI receive */ - if ( HAL_SPI_Receive_DMA(&spi, recv_buf, SPI_PKG_SIZE) != HAL_OK ) + if ( HAL_SPI_Receive_DMA(&spi, dma_recv_buf, sizeof(dma_recv_buf)) != HAL_OK ) { return -1; } @@ -238,10 +267,11 @@ int32_t spi_slave_send(uint8_t* buf, uint32_t size, int32_t timeout) { uint32_t msg_size; int32_t ret = 0; - msg_size = size < SPI_PKG_SIZE ? SPI_PKG_SIZE : size; - memcpy(send_buf, buf, msg_size); + msg_size = size; //< SPI_PKG_SIZE ? SPI_PKG_SIZE : size + memcpy(dma_send_buf, buf, msg_size); spi_abort_event = 1; + spi_data_dir_in = false; if ( HAL_SPI_Abort_IT(&spi) != HAL_OK ) { return 0; @@ -249,12 +279,12 @@ int32_t spi_slave_send(uint8_t* buf, uint32_t size, int32_t timeout) while ( spi_abort_event ) ; - if ( HAL_SPI_Transmit_DMA(&spi, send_buf, SPI_PKG_SIZE) != HAL_OK ) + if ( HAL_SPI_Transmit_DMA(&spi, dma_send_buf, msg_size) != HAL_OK ) { goto END; } - SET_COMBUS_LOW(); + ST_BLE_STATUS_IO_BUSY(); spi_tx_event = 1; @@ -267,16 +297,18 @@ int32_t spi_slave_send(uint8_t* buf, uint32_t size, int32_t timeout) if ( ret == 0 ) { HAL_SPI_Abort(&spi); - HAL_SPI_Receive_DMA(&spi, recv_buf, SPI_PKG_SIZE); + HAL_SPI_Receive_DMA(&spi, dma_recv_buf, sizeof(dma_recv_buf)); } - SET_COMBUS_HIGH(); + ST_BLE_STATUS_IO_IDLE(); + spi_data_dir_in = true; return ret; } -uint32_t spi_slave_poll(uint8_t* buf) +uint32_t _spi_slave_poll_ex(uint8_t* buf, bool fido) { - volatile uint32_t total_len, len, ret; + volatile uint32_t total_len, len; + uint8_t header[3]; if ( buf == NULL ) return 0; @@ -287,9 +319,43 @@ uint32_t spi_slave_poll(uint8_t* buf) return 0; } - len = total_len > SPI_PKG_SIZE ? SPI_PKG_SIZE : total_len; - ret = fifo_read_lock(&spi_fifo_in, buf, len); - return ret; + fifo_read_peek(&spi_fifo_in, header, sizeof(header)); + + if ( fido ) + { + if ( memcmp(header, "fid", 3) == 0 ) + { + fifo_read_lock(&spi_fifo_in, header, sizeof(header)); + // read len + fifo_read_lock(&spi_fifo_in, header, 2); + len = header[0] << 8 | header[1]; + fifo_read_lock(&spi_fifo_in, buf, total_len - 5); + if ( total_len - 5 < len ) + { + return 0; + } + return len; + } + } + else + { + if ( header[0] == '?' ) + { + len = total_len > SPI_PKG_SIZE ? SPI_PKG_SIZE : total_len; + return fifo_read_lock(&spi_fifo_in, buf, len); + } + } + return 0; +} + +uint32_t spi_slave_poll(uint8_t* buf) +{ + return _spi_slave_poll_ex(buf, false); +} + +uint32_t spi_slave_poll_fido(uint8_t* buf) +{ + return _spi_slave_poll_ex(buf, true); } uint32_t spi_read_retry(uint8_t* buf) @@ -354,3 +420,25 @@ void SPIx_DMA_TX_IRQHandler(void) { HAL_DMA_IRQHandler(spi.hdmatx); } + +void spi_cs_irq_handler(void) +{ + if ( HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == GPIO_PIN_RESET ) + { + return; + } + + if ( spi_data_dir_in ) + { + HAL_SPI_Abort(&spi); + uint16_t recv_len = sizeof(dma_recv_buf) - __HAL_DMA_GET_COUNTER(spi.hdmarx); + if ( recv_len > 0 ) + { + ST_BLE_STATUS_IO_BUSY(); + fifo_write_no_overflow(&spi_fifo_in, dma_recv_buf, recv_len); + ST_BLE_STATUS_IO_IDLE(); + } + + HAL_SPI_Receive_DMA(&spi, dma_recv_buf, sizeof(dma_recv_buf)); + } +} diff --git a/core/embed/trezorhal/spi_legacy.h b/core/embed/trezorhal/spi_legacy.h index db40b38e9f..c91a8b798b 100644 --- a/core/embed/trezorhal/spi_legacy.h +++ b/core/embed/trezorhal/spi_legacy.h @@ -4,33 +4,20 @@ #include #include #include "trans_fifo.h" +#include "dma_channel.h" -#define SPI_PKG_SIZE 64 -#define SPI_BUF_MAX_IN_LEN (16 * 1024) -#define SPI_BUF_MAX_OUT_LEN (3 * 1024) +#define SPI_PKG_SIZE 64 +#define SPI_BUF_MAX_IN_LEN (16 * 1024) +#define SPI_BUF_MAX_OUT_LEN (3 * 1024) -#define SET_COMBUS_HIGH() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_6, GPIO_PIN_SET) -#define SET_COMBUS_LOW() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_6, GPIO_PIN_RESET) +#define SET_COMBUS_HIGH() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_6, GPIO_PIN_SET) +#define SET_COMBUS_LOW() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_6, GPIO_PIN_RESET) -#define SET_RX_BUS_IDEL() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_6, GPIO_PIN_SET) -#define SET_RX_BUS_BUSY() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_6, GPIO_PIN_RESET) +#define ST_BLE_STATUS_IO_IDLE() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_6, GPIO_PIN_SET) +#define ST_BLE_STATUS_IO_BUSY() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_6, GPIO_PIN_RESET) -#define BLE_RST_PIN_HIGH() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_5, GPIO_PIN_SET) -#define BLE_RST_PIN_LOW() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_5, GPIO_PIN_RESET) - -/* Definition for SPIx's DMA */ -#define SPIx_TX_DMA_STREAM DMA1_Stream3 -#define SPIx_RX_DMA_STREAM DMA1_Stream2 - -#define SPIx_TX_DMA_REQUEST DMA_REQUEST_SPI2_TX -#define SPIx_RX_DMA_REQUEST DMA_REQUEST_SPI2_RX - -/* Definition for SPIx's NVIC */ -#define SPIx_DMA_TX_IRQn DMA1_Stream3_IRQn -#define SPIx_DMA_RX_IRQn DMA1_Stream2_IRQn - -#define SPIx_DMA_TX_IRQHandler DMA1_Stream3_IRQHandler -#define SPIx_DMA_RX_IRQHandler DMA1_Stream2_IRQHandler +#define BLE_RST_PIN_HIGH() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_5, GPIO_PIN_SET) +#define BLE_RST_PIN_LOW() HAL_GPIO_WritePin(GPIOK, GPIO_PIN_5, GPIO_PIN_RESET) typedef enum _ChannelType { @@ -51,6 +38,9 @@ uint32_t spi_slave_poll(uint8_t* buf); secbool spi_can_write(void); uint32_t spi_read_retry(uint8_t* buf); uint32_t spi_read_blocking(uint8_t* buf, int timeout); +void spi_cs_irq_handler(void); +uint32_t spi_slave_poll_fido(uint8_t* buf); + #endif #endif diff --git a/core/embed/trezorhal/stm32_it_handler.c b/core/embed/trezorhal/stm32_it_handler.c index d9542a1025..03c74bf9da 100644 --- a/core/embed/trezorhal/stm32_it_handler.c +++ b/core/embed/trezorhal/stm32_it_handler.c @@ -1,12 +1,23 @@ #include STM32_HAL_H +#if !BOOT_ONLY #include "fpsensor_driver.h" #include "fpsensor_platform.h" #include "gt911.h" +#endif +#include "spi_legacy.h" + +void EXTI2_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2); } +void EXTI15_10_IRQHandler(void) { + // fp sensor irq + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15); + // spi cs irq + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11); +} void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { +#if !BOOT_ONLY uint8_t irq_status[2]; - // fp sensor irq if (GPIO_Pin == GPIO_PIN_15) { fpsensor_read_irq_with_clear(irq_status, 2); @@ -20,4 +31,9 @@ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { gt911_read_location(); HAL_NVIC_DisableIRQ(EXTI2_IRQn); } -} \ No newline at end of file +#endif + // spi cs irq + if (GPIO_Pin == GPIO_PIN_11) { + spi_cs_irq_handler(); + } +} diff --git a/core/embed/trezorhal/usart.c b/core/embed/trezorhal/usart.c index bc6ca9d968..8e81e138f1 100644 --- a/core/embed/trezorhal/usart.c +++ b/core/embed/trezorhal/usart.c @@ -5,6 +5,7 @@ #include "ble.h" #include "common.h" +#include "dma_channel.h" #include "irq.h" #include "usart.h" @@ -13,9 +14,17 @@ UART_HandleTypeDef uart; UART_HandleTypeDef *huart = &uart; +static DMA_HandleTypeDef hdma_tx; +static DMA_HandleTypeDef hdma_rx; + +static bool uart_tx_done = false; + #define UART_PACKET_MAX_LEN 128 -uint8_t usart_fifo[UART_PACKET_MAX_LEN] = {0}; -uint8_t usart_fifo_len = 0; +static uint8_t dma_uart_rev_buf[UART_PACKET_MAX_LEN] + __attribute__((section(".sram3"))); +static uint8_t dma_uart_send_buf[UART_PACKET_MAX_LEN] + __attribute__((section(".sram3"))); +uint32_t usart_fifo_len = 0; uint8_t uart_data_in[UART_BUF_MAX_LEN]; @@ -38,6 +47,10 @@ void ble_usart_init(void) { __HAL_RCC_UART4_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_DMA1_FORCE_RESET(); + __HAL_RCC_DMA1_RELEASE_RESET(); + __HAL_RCC_DMA1_CLK_ENABLE(); + // UART4: PA0_C(TX), PA1_C(RX) GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; @@ -62,11 +75,51 @@ void ble_usart_init(void) { ensure(secfalse, "uart init failed"); } + // Configure DMA + hdma_tx.Instance = UARTx_TX_DMA_STREAM; + + hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_tx.Init.Request = UARTx_TX_DMA_REQUEST; + hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_tx.Init.Mode = DMA_NORMAL; + hdma_tx.Init.Priority = DMA_PRIORITY_MEDIUM; + + HAL_DMA_Init(&hdma_tx); + + __HAL_LINKDMA(huart, hdmatx, hdma_tx); + + hdma_rx.Instance = UARTx_RX_DMA_STREAM; + + hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_rx.Init.Request = UARTx_RX_DMA_REQUEST; + hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_rx.Init.Mode = DMA_NORMAL; + hdma_rx.Init.Priority = DMA_PRIORITY_MEDIUM; + + HAL_DMA_Init(&hdma_rx); + + __HAL_LINKDMA(huart, hdmarx, hdma_rx); + + /*##-4- Configure the NVIC for DMA #########################################*/ + NVIC_SetPriority(UARTx_DMA_RX_IRQn, IRQ_PRI_DMA); + HAL_NVIC_EnableIRQ(UARTx_DMA_RX_IRQn); + + NVIC_SetPriority(UARTx_DMA_TX_IRQn, IRQ_PRI_DMA); + HAL_NVIC_EnableIRQ(UARTx_DMA_TX_IRQn); + NVIC_SetPriority(UART4_IRQn, IRQ_PRI_UART); HAL_NVIC_EnableIRQ(UART4_IRQn); - __HAL_UART_ENABLE_IT(huart, UART_IT_RXFNE); - __HAL_UART_ENABLE_IT(huart, UART_IT_ERR); + __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE); + HAL_UART_Receive_DMA(huart, dma_uart_rev_buf, sizeof(dma_uart_rev_buf)); } void usart_enable_stop_wup(void) { @@ -88,7 +141,21 @@ void ble_usart_send_byte(uint8_t data) { } void ble_usart_send(uint8_t *buf, uint32_t len) { - HAL_UART_Transmit(huart, buf, len, 0xFFFF); + while (len > 0) { + uart_tx_done = false; + uint32_t send_len = len > UART_PACKET_MAX_LEN ? UART_PACKET_MAX_LEN : len; + memcpy(dma_uart_send_buf, buf, send_len); + HAL_UART_Transmit_DMA(huart, dma_uart_send_buf, send_len); + uint32_t start = HAL_GetTick(); + while (!uart_tx_done) { + if (HAL_GetTick() - start > 500) { + return; + } + __WFI(); + } + len -= send_len; + buf += send_len; + } } bool ble_read_byte(uint8_t *buf) { @@ -109,21 +176,11 @@ secbool ble_usart_can_read(void) { void ble_usart_irq_ctrl(bool enable) { if (enable) { HAL_NVIC_EnableIRQ(UART4_IRQn); - __HAL_UART_ENABLE_IT(huart, UART_IT_RXFNE); - __HAL_UART_ENABLE_IT(huart, UART_IT_ERR); + HAL_UART_Abort(huart); + HAL_UART_Receive_DMA(huart, dma_uart_rev_buf, sizeof(dma_uart_rev_buf)); } else { + HAL_UART_Abort(huart); HAL_NVIC_DisableIRQ(UART4_IRQn); - if (__HAL_UART_GET_FLAG(huart, UART_FLAG_WUF)) { - __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_WUF); - } - if (__HAL_UART_GET_FLAG(huart, UART_FLAG_RXFNE) != 0) { - volatile uint8_t data = 0; - data = (uint8_t)(huart->Instance->RDR); - (void)data; - } - if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != 0) { - __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); - } } } @@ -146,66 +203,84 @@ static uint8_t calXor(uint8_t *buf, uint32_t len) { return tmp; } -static HAL_StatusTypeDef usart_rev_bytes(uint8_t *buf, uint32_t len, - uint32_t timeout) { - for (int i = 0; i < len; i++) { - while (__HAL_UART_GET_FLAG(huart, UART_FLAG_RXFNE) == 0) { - timeout--; - if (timeout == 0) { - return HAL_TIMEOUT; - } +static void usart_rev_package_dma(uint8_t *buf, uint32_t len) { + if (len < 5) { + return; + } + uint32_t index = 0; + uint8_t *p_header; + while (len > 0) { + if (buf[index] != 0xA5 || buf[index + 1] != 0x5A) { + index++; + len--; + continue; } - buf[i] = (uint8_t)(huart->Instance->RDR); - timeout = USART_TIMEOUT; + p_header = buf + index; + index += 2; + len -= 2; + if (len < 2) { + return; + } + // length include xor byte + uint16_t data_len = (buf[index] << 8) + buf[index + 1]; + index += 2; + len -= 2; + if (len < data_len) { + return; + } + index += data_len; + len -= data_len; + + uint8_t xor = calXor(p_header, data_len + 3); + if (buf[index - 1] != xor) { + return; + } + fifo_write_no_overflow(&uart_fifo_in, p_header, data_len + 3); } - return HAL_OK; } -static void usart_rev_package(uint8_t *buf) { - uint8_t len = 0; - uint8_t *p_buf = buf; - if (usart_rev_bytes(p_buf, 2, USART_TIMEOUT) != HAL_OK) { - return; - } - if (p_buf[0] != 0xA5 || p_buf[1] != 0x5A) { - return; - } - p_buf += 2; - if (usart_rev_bytes(p_buf, 2, USART_TIMEOUT) != HAL_OK) { - return; - } - len = (p_buf[0] << 8) + p_buf[1]; - if (len > UART_PACKET_MAX_LEN - 4) { - return; - } - p_buf += 2; - if (usart_rev_bytes(p_buf, len - 1, USART_TIMEOUT) != HAL_OK) { - return; - } - p_buf += len - 1; - if (usart_rev_bytes(p_buf, 1, USART_TIMEOUT) != HAL_OK) { - return; - } - uint8_t xor = calXor(buf, len + 3); - if (xor != *p_buf) { - return; - } - fifo_write_no_overflow(&uart_fifo_in, buf, len + 3); +// void UART4_IRQHandler(void) { +// volatile uint8_t data = 0; +// (void)data; +// if (__HAL_UART_GET_FLAG(huart, UART_FLAG_WUF)) { +// __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_WUF); +// } +// if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != 0) { +// data = (uint8_t)(huart->Instance->RDR); +// __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); +// } +// if (__HAL_UART_GET_FLAG(huart, UART_FLAG_RXFNE) != 0) { +// memset(dma_uart_rev_buf, 0x00, sizeof(dma_uart_rev_buf)); +// usart_rev_package(dma_uart_rev_buf); +// } +// } + +void UARTx_DMA_TX_IRQHandler(void) { HAL_DMA_IRQHandler(huart->hdmatx); } + +void UARTx_DMA_RX_IRQHandler(void) { HAL_DMA_IRQHandler(huart->hdmarx); } + +void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { + usart_rev_package_dma(dma_uart_rev_buf, sizeof(dma_uart_rev_buf)); + HAL_UART_Receive_DMA(huart, dma_uart_rev_buf, sizeof(dma_uart_rev_buf)); } +void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { uart_tx_done = true; } + void UART4_IRQHandler(void) { - volatile uint8_t data = 0; - (void)data; if (__HAL_UART_GET_FLAG(huart, UART_FLAG_WUF)) { __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_WUF); } - if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != 0) { - data = (uint8_t)(huart->Instance->RDR); - __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); - } - if (__HAL_UART_GET_FLAG(huart, UART_FLAG_RXFNE) != 0) { - memset(usart_fifo, 0x00, sizeof(usart_fifo)); - usart_rev_package(usart_fifo); + if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE)) { + __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_IDLE); + HAL_UART_Abort(huart); + usart_fifo_len = + sizeof(dma_uart_rev_buf) - __HAL_DMA_GET_COUNTER(huart->hdmarx); + if (usart_fifo_len > 0) { + usart_rev_package_dma(dma_uart_rev_buf, usart_fifo_len); + } + HAL_UART_Receive_DMA(huart, dma_uart_rev_buf, sizeof(dma_uart_rev_buf)); + } else { + HAL_UART_IRQHandler(huart); } } diff --git a/core/mocks/generated/trezorio/__init__.pyi b/core/mocks/generated/trezorio/__init__.pyi index 69a92ade01..e1304099f5 100644 --- a/core/mocks/generated/trezorio/__init__.pyi +++ b/core/mocks/generated/trezorio/__init__.pyi @@ -304,6 +304,8 @@ BUTTON_PRESSED: int # button down event BUTTON_RELEASED: int # button up event BUTTON_LEFT: int # button number of left button BUTTON_RIGHT: int # button number of right button +SPI_FACE: int # interface id of the spi events +SPI_FIDO_FACE: int # interface id of the spi fido events WireInterface = Union[HID, WebUSB, SPI] USB_CHECK: int # interface id for check of USB data connection FINGERPRINT_STATE: int # interface id of the fingerprint state events diff --git a/core/src/apps/webauthn/__init__.py b/core/src/apps/webauthn/__init__.py index 401ce0d615..bf7d0bf9cf 100644 --- a/core/src/apps/webauthn/__init__.py +++ b/core/src/apps/webauthn/__init__.py @@ -1,4 +1,4 @@ -from trezor import loop +from trezor import io, loop import usb @@ -6,4 +6,4 @@ def boot() -> None: - loop.schedule(handle_reports(usb.iface_webauthn)) + loop.schedule(handle_reports(usb.iface_webauthn, io.SPI(io.SPI_FIDO_FACE))) diff --git a/core/src/apps/webauthn/credential.py b/core/src/apps/webauthn/credential.py index 2f4153c413..26ba28b44f 100644 --- a/core/src/apps/webauthn/credential.py +++ b/core/src/apps/webauthn/credential.py @@ -16,7 +16,7 @@ # Credential ID values _CRED_ID_VERSION = b"\xf1\xd0\x02\x00" CRED_ID_MIN_LENGTH = const(33) -CRED_ID_MAX_LENGTH = const(1024) +CRED_ID_MAX_LENGTH = const(512) _KEY_HANDLE_LENGTH = const(64) # Maximum user handle length in bytes. diff --git a/core/src/apps/webauthn/fido2.py b/core/src/apps/webauthn/fido2.py index e0d2d844fc..55de781704 100644 --- a/core/src/apps/webauthn/fido2.py +++ b/core/src/apps/webauthn/fido2.py @@ -22,6 +22,9 @@ from .credential import CRED_ID_MAX_LENGTH, Credential, Fido2Credential, U2fCredential from .resident_credentials import find_by_rp_id_hash, store_resident_credential +_IFACE_HID = const(0) +_IFACE_SPI = const(1) + _CID_BROADCAST = const(0xFFFF_FFFF) # broadcast channel id # types of frame @@ -44,9 +47,11 @@ _CMD_WINK = const(0x88) # send device identification wink _CMD_CBOR = const(0x90) # send encapsulated CTAP CBOR encoded message _CMD_CANCEL = const(0x91) # cancel any outstanding requests on this CID -_CMD_KEEPALIVE = const(0xBB) # processing a message +_CMD_KEEPALIVE = _CMD_KEEPALIVE_HID = const(0xBB) # processing a message _CMD_ERROR = const(0xBF) # error response +_CMD_KEEPALIVE_BLE = const(0x82) + # types for the msg cmd _MSG_REGISTER = const(0x01) # registration command _MSG_AUTHENTICATE = const(0x02) # authenticate/sign command @@ -372,7 +377,7 @@ def to_msg(self) -> Msg: return Msg(self.cid, cla, ins, p1, p2, lc, data) -async def read_cmd(iface: io.HID) -> Cmd | None: +async def read_cmd(iface: io.HID) -> tuple[int, Cmd] | None: desc_init = frame_init() desc_cont = frame_cont() read = loop.wait(iface.iface_num() | io.POLL_READ) @@ -474,10 +479,10 @@ async def read_cmd(iface: io.HID) -> Cmd | None: datalen += utils.memcpy(data, datalen, cfrm.data, 0, bcnt - datalen) seq += 1 else: - return Cmd(ifrm.cid, ifrm.cmd, bytes(data)) + return _IFACE_HID, Cmd(ifrm.cid, ifrm.cmd, bytes(data)) -async def send_cmd(cmd: Cmd, iface: io.HID) -> None: +async def send_cmd_hid(cmd: Cmd, iface: io.HID) -> None: init_desc = frame_init() cont_desc = frame_cont() offset = 0 @@ -512,7 +517,7 @@ async def send_cmd(cmd: Cmd, iface: io.HID) -> None: seq += 1 -def send_cmd_sync(cmd: Cmd, iface: io.HID) -> None: +def send_cmd_sync_hid(cmd: Cmd, iface: io.HID) -> None: init_desc = frame_init() cont_desc = frame_cont() offset = 0 @@ -540,34 +545,114 @@ def send_cmd_sync(cmd: Cmd, iface: io.HID) -> None: seq += 1 -async def handle_reports(iface: io.HID) -> None: - dialog_mgr = DialogManager(iface) +async def send_cmd_ble(cmd: Cmd, iface: io.SPI) -> None: + buf = bytearray(8 + len(cmd.data)) + # SPI EXTRA HEADER + buf[0:3] = b"fid" + buf[3] = (len(cmd.data) + 3) >> 8 + buf[4] = (len(cmd.data) + 3) & 0xFF + # BLE CMD + buf[5] = cmd.cmd + buf[6] = len(cmd.data) >> 8 + buf[7] = len(cmd.data) & 0xFF + buf[8:] = cmd.data + write = loop.wait(iface.iface_num() | io.POLL_WRITE) + + await write + iface.write(buf) + + +def send_cmd_sync_ble(cmd: Cmd, iface: io.SPI) -> None: + buf = bytearray(8 + len(cmd.data)) + buf[0:3] = b"fid" + buf[3] = (len(cmd.data) + 3) >> 8 + buf[4] = (len(cmd.data) + 3) & 0xFF + buf[5] = cmd.cmd + buf[6] = len(cmd.data) >> 8 + buf[7] = len(cmd.data) & 0xFF + buf[8:] = cmd.data + iface.write(buf) + + +async def read_spi_cmd(iface: io.SPI) -> tuple[int, Cmd] | None: + read = loop.wait(iface.iface_num() | io.POLL_READ) + buf = await read + cmd = buf[0] + data_len = (buf[1] << 8) | buf[2] + data = buf[3:] + if len(data) != data_len: + await send_cmd_ble(cmd_error(0, _ERR_INVALID_LEN), iface) + return None + return _IFACE_SPI, Cmd(0, cmd, data) + + +async def send_cmd(cmd: Cmd, iface: io.HID | io.SPI) -> None: + if isinstance(iface, io.HID): + await send_cmd_hid(cmd, iface) + elif isinstance(iface, io.SPI): + if cmd.cmd == _CMD_CBOR: + cmd.cmd = _CMD_MSG + await send_cmd_ble(cmd, iface) + + +def send_cmd_sync(cmd: Cmd, iface: io.HID | io.SPI) -> None: + if isinstance(iface, io.HID): + send_cmd_sync_hid(cmd, iface) + elif isinstance(iface, io.SPI): + send_cmd_sync_ble(cmd, iface) + + +async def handle_reports(usb_face: io.HID, spi_iface: io.SPI) -> None: + import gc + + dialog_mgr = DialogManager(usb_face) while True: try: - req = await read_cmd(iface) + result = await loop.race(read_cmd(usb_face), read_spi_cmd(spi_iface)) + if result is None: + continue + face, req = result + if face == _IFACE_HID: + dialog_mgr.set_iface(usb_face) + elif face == _IFACE_SPI: + dialog_mgr.set_iface(spi_iface) + if req is None: continue - if dialog_mgr.is_busy() and req.cid not in ( - dialog_mgr.get_cid(), - _CID_BROADCAST, + if dialog_mgr.is_busy() and ( + req.cid + not in ( + dialog_mgr.get_cid(), + _CID_BROADCAST, + ) + and dialog_mgr.iface == usb_face ): resp: Cmd | None = cmd_error(req.cid, _ERR_CHANNEL_BUSY) else: resp = dispatch_cmd(req, dialog_mgr) if resp is not None: - await send_cmd(resp, iface) + await send_cmd(resp, dialog_mgr.iface) + + if __debug__: + log.debug(__name__, f"mem_info before gc.collect(): {gc.mem_free()}") # type: ignore["mem_free" is not a known member of module] + gc.collect() + if __debug__: + log.debug(__name__, f"mem_info after gc.collect(): {gc.mem_free()} ") # type: ignore["mem_free" is not a known member of module] except Exception as e: log.exception(__name__, e) class KeepaliveCallback: - def __init__(self, cid: int, iface: io.HID) -> None: + def __init__(self, cid: int, iface: io.HID | io.SPI) -> None: self.cid = cid self.iface = iface def __call__(self) -> None: - send_cmd_sync(cmd_keepalive(self.cid, _KEEPALIVE_STATUS_PROCESSING), self.iface) + send_cmd_sync( + cmd_keepalive(self.cid, _KEEPALIVE_STATUS_PROCESSING, self.iface), + self.iface, + ) async def verify_user(keepalive_callback: KeepaliveCallback) -> bool: @@ -606,7 +691,7 @@ async def se_gen_seed(keepalive_callback: KeepaliveCallback) -> bool: class State: - def __init__(self, cid: int, iface: io.HID) -> None: + def __init__(self, cid: int, iface: io.HID | io.SPI) -> None: self.cid = cid self.iface = iface self.finished = False @@ -636,7 +721,7 @@ async def on_cancel(self) -> None: class U2fState(State, ConfirmInfo): def __init__( - self, cid: int, iface: io.HID, req_data: bytes, cred: Credential + self, cid: int, iface: io.HID | io.SPI, req_data: bytes, cred: Credential ) -> None: State.__init__(self, cid, iface) ConfirmInfo.__init__(self) @@ -656,7 +741,7 @@ def account_name(self) -> str | None: class U2fConfirmRegister(U2fState): def __init__( - self, cid: int, iface: io.HID, req_data: bytes, cred: U2fCredential + self, cid: int, iface: io.HID | io.SPI, req_data: bytes, cred: U2fCredential ) -> None: super().__init__(cid, iface, req_data, cred) @@ -693,7 +778,7 @@ def __eq__(self, other: object) -> bool: class U2fConfirmAuthenticate(U2fState): def __init__( - self, cid: int, iface: io.HID, req_data: bytes, cred: Credential + self, cid: int, iface: io.HID | io.SPI, req_data: bytes, cred: Credential ) -> None: super().__init__(cid, iface, req_data, cred) @@ -751,7 +836,7 @@ def __eq__(self, other: object) -> bool: class Fido2State(State): - def __init__(self, cid: int, iface: io.HID) -> None: + def __init__(self, cid: int, iface: io.HID | io.SPI) -> None: super().__init__(cid, iface) def keepalive_status(self) -> int: @@ -797,9 +882,8 @@ async def confirm_dialog(self) -> bool | "State": if not await verify_user(KeepaliveCallback(self.cid, self.iface)): return False if not await se_gen_seed(KeepaliveCallback(self.cid, self.iface)): + set_homescreen() return False - - set_homescreen() resp = self.process_func(self.req, self.dialog_mgr) if isinstance(resp, State): return resp @@ -816,7 +900,7 @@ class Fido2ConfirmMakeCredential(Fido2State, ConfirmInfo): def __init__( self, cid: int, - iface: io.HID, + iface: io.HID | io.SPI, client_data_hash: bytes, cred: Fido2Credential, resident: bool, @@ -848,7 +932,10 @@ async def confirm_dialog(self) -> bool: async def on_confirm(self) -> None: self._cred.generate_id() - send_cmd_sync(cmd_keepalive(self.cid, _KEEPALIVE_STATUS_PROCESSING), self.iface) + send_cmd_sync( + cmd_keepalive(self.cid, _KEEPALIVE_STATUS_PROCESSING, self.iface), + self.iface, + ) response_data = cbor_make_credential_sign( self._client_data_hash, self._cred, self._user_verification ) @@ -856,7 +943,8 @@ async def on_confirm(self) -> None: success = True if self._resident: send_cmd_sync( - cmd_keepalive(self.cid, _KEEPALIVE_STATUS_PROCESSING), self.iface + cmd_keepalive(self.cid, _KEEPALIVE_STATUS_PROCESSING, self.iface), + self.iface, ) from trezor.ui.layouts.lvgl import show_popup @@ -883,7 +971,7 @@ async def on_confirm(self) -> None: class Fido2ConfirmExcluded(Fido2ConfirmMakeCredential): - def __init__(self, cid: int, iface: io.HID, cred: Fido2Credential) -> None: + def __init__(self, cid: int, iface: io.HID | io.SPI, cred: Fido2Credential) -> None: super().__init__(cid, iface, b"", cred, resident=False, user_verification=False) async def on_confirm(self) -> None: @@ -906,7 +994,7 @@ class Fido2ConfirmGetAssertion(Fido2State, ConfirmInfo, Pageable): def __init__( self, cid: int, - iface: io.HID, + iface: io.HID | io.SPI, client_data_hash: bytes, creds: list[Credential], hmac_secret: dict | None, @@ -946,7 +1034,8 @@ async def on_confirm(self) -> None: cred = self._creds[self.page()] try: send_cmd_sync( - cmd_keepalive(self.cid, _KEEPALIVE_STATUS_PROCESSING), self.iface + cmd_keepalive(self.cid, _KEEPALIVE_STATUS_PROCESSING, self.iface), + self.iface, ) response_data = cbor_get_assertion_sign( self._client_data_hash, @@ -991,7 +1080,7 @@ async def confirm_dialog(self) -> bool: class Fido2ConfirmNoCredentials(Fido2ConfirmGetAssertion): - def __init__(self, cid: int, iface: io.HID, rp_id: str) -> None: + def __init__(self, cid: int, iface: io.HID | io.SPI, rp_id: str) -> None: cred = Fido2Credential() cred.rp_id = rp_id super().__init__( @@ -1015,7 +1104,7 @@ async def on_confirm(self) -> None: class Fido2ConfirmReset(Fido2State): - def __init__(self, cid: int, iface: io.HID) -> None: + def __init__(self, cid: int, iface: io.HID | io.SPI) -> None: super().__init__(cid, iface) async def confirm_dialog(self) -> bool: @@ -1030,7 +1119,7 @@ async def on_confirm(self) -> None: class DialogManager: - def __init__(self, iface: io.HID) -> None: + def __init__(self, iface) -> None: self.iface = iface self._clear() @@ -1041,6 +1130,9 @@ def _clear(self) -> None: self.workflow: loop.spawn | None = None self.keepalive: Coroutine | None = None + def set_iface(self, iface) -> None: + self.iface = iface + def _workflow_is_running(self) -> bool: return self.workflow is not None and not self.workflow.finished @@ -1095,7 +1187,9 @@ async def keepalive_loop(self) -> None: return while utime.ticks_ms() < self.deadline: if self.state.keepalive_status() != _KEEPALIVE_STATUS_NONE: - cmd = cmd_keepalive(self.state.cid, self.state.keepalive_status()) + cmd = cmd_keepalive( + self.state.cid, self.state.keepalive_status(), self.iface + ) await send_cmd(cmd, self.iface) await loop.sleep(_KEEPALIVE_INTERVAL_MS) finally: @@ -1132,7 +1226,7 @@ async def dialog_workflow(self) -> None: await self.state.on_decline() -def dispatch_cmd(req: Cmd, dialog_mgr: DialogManager) -> Cmd | None: +def dispatch_cmd_hid(req: Cmd, dialog_mgr: DialogManager) -> Cmd | None: if req.cmd == _CMD_MSG: try: m = req.to_msg() @@ -1222,6 +1316,105 @@ def dispatch_cmd(req: Cmd, dialog_mgr: DialogManager) -> Cmd | None: return cmd_error(req.cid, _ERR_INVALID_CMD) +def dispatch_cmd_ble(req: Cmd, dialog_mgr: DialogManager) -> Cmd | None: + if req.cmd == _CMD_MSG: + if req.data[0] == 0 or req.data[0] == 0x80: + try: + m = req.to_msg() + except IndexError: + return cmd_error(req.cid, _ERR_INVALID_LEN) + + if m.cla != 0: + if __debug__: + log.warning(__name__, "_SW_CLA_NOT_SUPPORTED") + return msg_error(req.cid, _SW_CLA_NOT_SUPPORTED) + + if m.lc + _APDU_DATA > len(req.data): + if __debug__: + log.warning(__name__, "_SW_WRONG_LENGTH") + return msg_error(req.cid, _SW_WRONG_LENGTH) + + if m.ins == _MSG_REGISTER: + if __debug__: + log.debug(__name__, "_MSG_REGISTER") + return msg_register(m, dialog_mgr) + elif m.ins == _MSG_AUTHENTICATE: + if __debug__: + log.debug(__name__, "_MSG_AUTHENTICATE") + return msg_authenticate(m, dialog_mgr) + elif m.ins == _MSG_VERSION: + if __debug__: + log.debug(__name__, "_MSG_VERSION") + return msg_version(m) + else: + if __debug__: + log.warning(__name__, "_SW_INS_NOT_SUPPORTED: %d", m.ins) + return msg_error(req.cid, _SW_INS_NOT_SUPPORTED) + elif _ALLOW_FIDO2: + if not req.data: + return cmd_error(req.cid, _ERR_INVALID_LEN) + if req.data[0] == _CBOR_MAKE_CREDENTIAL: + if __debug__: + log.debug(__name__, "_CBOR_MAKE_CREDENTIAL") + return cbor_make_credential(req, dialog_mgr) + elif req.data[0] == _CBOR_GET_ASSERTION: + if __debug__: + log.debug(__name__, "_CBOR_GET_ASSERTION") + return cbor_get_assertion(req, dialog_mgr) + elif req.data[0] == _CBOR_GET_INFO: + if __debug__: + log.debug(__name__, "_CBOR_GET_INFO") + return cbor_get_info(req) + elif req.data[0] == _CBOR_CLIENT_PIN: + if __debug__: + log.debug(__name__, "_CBOR_CLIENT_PIN") + return cbor_client_pin(req) + elif req.data[0] == _CBOR_RESET: + if __debug__: + log.debug(__name__, "_CBOR_RESET") + return cbor_reset(req, dialog_mgr) + elif req.data[0] == _CBOR_GET_NEXT_ASSERTION: + if __debug__: + log.debug(__name__, "_CBOR_GET_NEXT_ASSERTION") + return cbor_error(req.cid, _ERR_NOT_ALLOWED) + else: + if __debug__: + log.warning(__name__, "_ERR_INVALID_CMD _CMD_CBOR %d", req.data[0]) + return cbor_error(req.cid, _ERR_INVALID_CMD) + else: + if __debug__: + log.warning(__name__, "_ERR_INVALID_CMD _CMD_CBOR %d", req.data[0]) + return cbor_error(req.cid, _ERR_INVALID_CMD) + + elif req.cmd == _CMD_PING: + if __debug__: + log.debug(__name__, "_CMD_PING") + return req + elif req.cmd == _CMD_WINK and _ALLOW_WINK: + if __debug__: + log.debug(__name__, "_CMD_WINK") + return cmd_wink(req) + elif req.cmd == _CMD_CANCEL: + if __debug__: + log.debug(__name__, "_CMD_CANCEL") + dialog_mgr.result = _RESULT_CANCEL + dialog_mgr.reset() + return None + else: + if __debug__: + log.warning(__name__, "_ERR_INVALID_CMD: %d", req.cmd) + return cmd_error(req.cid, _ERR_INVALID_CMD) + + +def dispatch_cmd(req: Cmd, dialog_mgr: DialogManager) -> Cmd | None: + if isinstance(dialog_mgr.iface, io.HID): + return dispatch_cmd_hid(req, dialog_mgr) + elif isinstance(dialog_mgr.iface, io.SPI): + return dispatch_cmd_ble(req, dialog_mgr) + else: + return None + + def cmd_init(req: Cmd) -> Cmd: if req.cid == _CID_BROADCAST: # uint32_t except 0 and 0xffff_ffff @@ -1978,5 +2171,10 @@ def cbor_reset(req: Cmd, dialog_mgr: DialogManager) -> Cmd | None: return None -def cmd_keepalive(cid: int, status: int) -> Cmd: - return Cmd(cid, _CMD_KEEPALIVE, bytes([status])) +def cmd_keepalive(cid: int, status: int, iface: io.HID | io.SPI) -> Cmd: + if isinstance(iface, io.HID): + return Cmd(cid, _CMD_KEEPALIVE_HID, bytes([status])) + elif isinstance(iface, io.SPI): + return Cmd(cid, _CMD_KEEPALIVE_BLE, bytes([status])) + else: + raise ValueError("Invalid interface type") diff --git a/core/src/trezor/utils.py b/core/src/trezor/utils.py index e7d366394c..4cfc999eb6 100644 --- a/core/src/trezor/utils.py +++ b/core/src/trezor/utils.py @@ -109,8 +109,6 @@ def board_version() -> str: SCREENS = [] -SPI_IFACE_NUM = 6 - def set_up() -> None: from trezor import wire, io @@ -124,7 +122,7 @@ def set_up() -> None: wire.setup( io.SPI( - SPI_IFACE_NUM, + io.SPI_FACE, ) ) @@ -218,11 +216,11 @@ async def turn_off_lcd(): def play_dead(): - from trezor import loop + from trezor import io, loop import usb loop.pop_tasks_on_iface(usb.iface_wire.iface_num()) - loop.pop_tasks_on_iface(SPI_IFACE_NUM) + loop.pop_tasks_on_iface(io.SPI_FACE) def is_low_battery(): diff --git a/core/src/trezor/wire/__init__.py b/core/src/trezor/wire/__init__.py index baa820ad98..2733335423 100644 --- a/core/src/trezor/wire/__init__.py +++ b/core/src/trezor/wire/__init__.py @@ -38,7 +38,7 @@ from typing import TYPE_CHECKING from storage.cache import InvalidSessionError -from trezor import log, loop, protobuf, utils, workflow +from trezor import io, log, loop, protobuf, utils, workflow from trezor.enums import FailureType from trezor.messages import ButtonRequest, Failure from trezor.wire import codec_v1 @@ -377,7 +377,7 @@ def wait(self, *tasks: Awaitable) -> Any: async def signal(self): await SIGNAL_CHANNEL.take() - if self.iface.iface_num() == utils.SPI_IFACE_NUM: + if self.iface.iface_num() == io.SPI_FACE: await self.write(failure(loop.TASK_CLOSED)) SIGNAL_CHANNEL.publish("done")