mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-12 14:16:06 +00:00
feat(core): add BLE to bootloader
[no changelog]
This commit is contained in:
parent
e997dcea32
commit
5a68da1d23
@ -11,7 +11,7 @@ PRODUCTION = 0 if BOOTLOADER_QA else ARGUMENTS.get('PRODUCTION', '0') == '1'
|
||||
HW_REVISION = ARGUMENTS.get('HW_REVISION', None)
|
||||
UI_DEBUG_OVERLAY = ARGUMENTS.get('UI_DEBUG_OVERLAY', '0') == '1'
|
||||
|
||||
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga", "dma2d"]
|
||||
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga", "dma2d", "ble"]
|
||||
|
||||
CCFLAGS_MOD = ''
|
||||
CPPPATH_MOD = []
|
||||
@ -116,8 +116,10 @@ SOURCE_BOOTLOADER = [
|
||||
'embed/projects/bootloader/workflow/wf_empty_device.c',
|
||||
'embed/projects/bootloader/workflow/wf_auto_update.c',
|
||||
'embed/projects/bootloader/workflow/wf_host_control.c',
|
||||
'embed/projects/bootloader/workflow/wf_ble_pairing_request.c',
|
||||
'embed/projects/bootloader/wire/codec_v1.c',
|
||||
'embed/projects/bootloader/wire/wire_iface_usb.c',
|
||||
'embed/projects/bootloader/wire/wire_iface_ble.c',
|
||||
'embed/projects/bootloader/protob/protob.c',
|
||||
'embed/projects/bootloader/protob/pb/messages.pb.c',
|
||||
'embed/projects/bootloader/version_check.c',
|
||||
|
@ -59,6 +59,9 @@
|
||||
#ifdef USE_TAMPER
|
||||
#include <sys/tamper.h>
|
||||
#endif
|
||||
#ifdef USE_BLE
|
||||
#include <io/ble.h>
|
||||
#endif
|
||||
|
||||
#include "antiglitch.h"
|
||||
#include "bootui.h"
|
||||
@ -122,6 +125,9 @@ static void drivers_init(secbool *touch_initialized) {
|
||||
#ifdef USE_RGB_LED
|
||||
rgb_led_init();
|
||||
#endif
|
||||
#ifdef USE_BLE
|
||||
ble_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void drivers_deinit(void) {
|
||||
|
@ -18,17 +18,30 @@
|
||||
*/
|
||||
|
||||
#include <trezor_bsp.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include "poll.h"
|
||||
|
||||
#include <io/usb.h>
|
||||
#include <sys/systick.h>
|
||||
|
||||
#ifdef USE_BLE
|
||||
#include <io/ble.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
#include <io/button.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_TOUCH
|
||||
#include <io/touch.h>
|
||||
#endif
|
||||
|
||||
#ifdef TREZOR_EMULATOR
|
||||
#include "SDL.h"
|
||||
#endif
|
||||
|
||||
uint8_t poll_events(const uint16_t* ifaces, size_t ifaces_num,
|
||||
int16_t poll_events(const uint16_t* ifaces, size_t ifaces_num,
|
||||
poll_event_t* event, uint32_t timeout_ms) {
|
||||
uint32_t deadline = ticks_timeout(timeout_ms);
|
||||
|
||||
@ -45,11 +58,41 @@ uint8_t poll_events(const uint16_t* ifaces, size_t ifaces_num,
|
||||
if ((ifaces[i] & MODE_READ) == MODE_READ) {
|
||||
// check if USB can read
|
||||
if (sectrue == usb_webusb_can_read(iface_num)) {
|
||||
event->type = EVENT_USB_CAN_READ;
|
||||
event->event.usb_data_event = EVENT_USB_CAN_READ;
|
||||
return iface_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef USE_BLE
|
||||
if (iface_num == IFACE_BLE) {
|
||||
if ((ifaces[i] & MODE_READ) == MODE_READ) {
|
||||
// check if BLE can read
|
||||
if (ble_can_read()) {
|
||||
event->event.ble_data_event = EVENT_BLE_CAN_READ;
|
||||
return iface_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (iface_num == IFACE_BLE_EVENT) {
|
||||
ble_event_t ble_event = {0};
|
||||
if (ble_get_event(&ble_event)) {
|
||||
memcpy(&event->event.ble_event, &ble_event, sizeof(ble_event_t));
|
||||
return iface_num;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_BUTTON
|
||||
if (iface_num == IFACE_BUTTON) {
|
||||
uint32_t btn_event = button_get_event();
|
||||
uint32_t etype = (btn_event >> 24) & 0x3U; // button down/up
|
||||
uint32_t btn_number = btn_event & 0xFFFF;
|
||||
if (etype != 0) {
|
||||
event->event.button_event.type = etype;
|
||||
event->event.button_event.button = btn_number;
|
||||
return iface_num;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef TREZOR_EMULATOR
|
||||
@ -57,6 +100,5 @@ uint8_t poll_events(const uint16_t* ifaces, size_t ifaces_num,
|
||||
#endif
|
||||
}
|
||||
|
||||
event->type = EVENT_NONE;
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
@ -21,19 +21,55 @@
|
||||
|
||||
#include <trezor_types.h>
|
||||
|
||||
#include <io/usb.h>
|
||||
|
||||
#ifdef USE_BLE
|
||||
#include <io/ble.h>
|
||||
#endif
|
||||
#ifdef USE_BUTTON
|
||||
#include <io/button.h>
|
||||
#endif
|
||||
|
||||
#define IFACE_USB_MAX (15) // 0-15 reserved for USB
|
||||
#define IFACE_BLE (16)
|
||||
#define IFACE_BLE_EVENT (252)
|
||||
#define IFACE_BUTTON (254)
|
||||
#define IFACE_TOUCH (255)
|
||||
|
||||
#define MODE_READ 0x0000
|
||||
#define MODE_WRITE 0x0100
|
||||
|
||||
typedef enum {
|
||||
EVENT_NONE = 0,
|
||||
EVENT_USB_CAN_READ = 0x01,
|
||||
} poll_event_type_t;
|
||||
EVENT_USB_CAN_READ,
|
||||
} usb_data_event_type_t;
|
||||
|
||||
#ifdef USE_BLE
|
||||
typedef enum {
|
||||
EVENT_BLE_CAN_READ,
|
||||
} ble_data_event_type_t;
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
button_t button;
|
||||
} button_event_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
poll_event_type_t type;
|
||||
union {
|
||||
usb_data_event_type_t usb_data_event;
|
||||
usb_event_t usb_event;
|
||||
#ifdef USE_BLE
|
||||
ble_data_event_type_t ble_data_event;
|
||||
ble_event_t ble_event;
|
||||
#endif
|
||||
#ifdef USE_BUTTON
|
||||
button_event_t button_event;
|
||||
#endif
|
||||
|
||||
} event;
|
||||
} poll_event_t;
|
||||
|
||||
uint8_t poll_events(const uint16_t* ifaces, size_t ifaces_num,
|
||||
int16_t poll_events(const uint16_t* ifaces, size_t ifaces_num,
|
||||
poll_event_t* event, uint32_t timeout_ms);
|
||||
|
116
core/embed/projects/bootloader/wire/wire_iface_ble.c
Normal file
116
core/embed/projects/bootloader/wire/wire_iface_ble.c
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include "wire_iface_ble.h"
|
||||
|
||||
#include <io/ble.h>
|
||||
#include <sys/systick.h>
|
||||
|
||||
static bool ble_write_(uint8_t* data, size_t size) {
|
||||
if (size != BLE_TX_PACKET_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t deadline = ticks_timeout(500);
|
||||
|
||||
while (true) {
|
||||
if (ticks_expired(deadline)) {
|
||||
return false;
|
||||
}
|
||||
if (ble_can_write()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ble_write(data, size);
|
||||
}
|
||||
|
||||
static int ble_read_(uint8_t* buffer, size_t buffer_size) {
|
||||
if (buffer_size != BLE_RX_PACKET_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t deadline = ticks_timeout(500);
|
||||
|
||||
while (true) {
|
||||
if (ticks_expired(deadline)) {
|
||||
return false;
|
||||
}
|
||||
if (ble_can_read()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int r = ble_read(buffer, buffer_size);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void ble_error(void) {
|
||||
error_shutdown_ex("BLE ERROR",
|
||||
"Error reading from BLE. Try different BLE cable.", NULL);
|
||||
}
|
||||
|
||||
void ble_iface_init(wire_iface_t* iface) {
|
||||
ble_start();
|
||||
|
||||
memset(iface, 0, sizeof(wire_iface_t));
|
||||
|
||||
iface->poll_iface_id = 16;
|
||||
iface->tx_packet_size = BLE_TX_PACKET_SIZE;
|
||||
iface->rx_packet_size = BLE_RX_PACKET_SIZE;
|
||||
iface->write = &ble_write_;
|
||||
iface->read = &ble_read_;
|
||||
iface->error = &ble_error;
|
||||
|
||||
ble_start();
|
||||
|
||||
ble_state_t state = {0};
|
||||
|
||||
ble_get_state(&state);
|
||||
|
||||
if (!state.connectable && !state.pairing) {
|
||||
if (state.peer_count > 0) {
|
||||
ble_command_t cmd = {
|
||||
.cmd_type = BLE_SWITCH_ON,
|
||||
};
|
||||
ble_issue_command(&cmd);
|
||||
} else {
|
||||
ble_iface_start_pairing();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ble_iface_deinit(wire_iface_t* iface) { ble_stop(); }
|
||||
|
||||
void ble_iface_start_pairing(void) {
|
||||
ble_command_t cmd = {
|
||||
.cmd_type = BLE_PAIRING_MODE,
|
||||
.data = {.adv_start =
|
||||
{
|
||||
.name = "Trezor Bootloader",
|
||||
.static_mac = false,
|
||||
}},
|
||||
.data_len = 0,
|
||||
};
|
||||
ble_issue_command(&cmd);
|
||||
}
|
28
core/embed/projects/bootloader/wire/wire_iface_ble.h
Normal file
28
core/embed/projects/bootloader/wire/wire_iface_ble.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "codec_v1.h"
|
||||
|
||||
void ble_iface_init(wire_iface_t* iface);
|
||||
|
||||
void ble_iface_deinit(wire_iface_t* iface);
|
||||
|
||||
void ble_iface_start_pairing(void);
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef USE_BLE
|
||||
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <io/ble.h>
|
||||
|
||||
#include "bootui.h"
|
||||
#include "rust_ui_bootloader.h"
|
||||
#include "workflow.h"
|
||||
|
||||
workflow_result_t workflow_ble_pairing_request(const uint8_t *data) {
|
||||
ui_result_t result = screen_confirm_pairing(data);
|
||||
|
||||
if (result == UI_RESULT_CONFIRM) {
|
||||
ble_command_t cmd = {
|
||||
.cmd_type = BLE_ALLOW_PAIRING,
|
||||
};
|
||||
ble_issue_command(&cmd);
|
||||
} else {
|
||||
ble_command_t cmd = {
|
||||
.cmd_type = BLE_REJECT_PAIRING,
|
||||
};
|
||||
ble_issue_command(&cmd);
|
||||
}
|
||||
|
||||
screen_connect(false);
|
||||
return WF_OK;
|
||||
}
|
||||
|
||||
#endif
|
@ -521,9 +521,9 @@ workflow_result_t workflow_firmware_update(protob_io_t *iface) {
|
||||
while (true) {
|
||||
uint16_t ifaces[1] = {protob_get_iface_flag(iface) | MODE_READ};
|
||||
poll_event_t e = {0};
|
||||
uint8_t i = poll_events(ifaces, 1, &e, 100);
|
||||
uint16_t i = poll_events(ifaces, 1, &e, 100);
|
||||
|
||||
if (e.type == EVENT_NONE || i != protob_get_iface_flag(iface)) {
|
||||
if (i < 0 || i != protob_get_iface_flag(iface)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -30,11 +30,21 @@
|
||||
#include "wire/wire_iface_usb.h"
|
||||
#include "workflow.h"
|
||||
|
||||
#ifdef USE_BLE
|
||||
#include <wire/wire_iface_ble.h>
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
#include <io/button.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
workflow_result_t workflow_host_control(const vendor_header *const vhdr,
|
||||
const image_header *const hdr,
|
||||
void (*redraw_wait_screen)(void)) {
|
||||
wire_iface_t usb_iface = {0};
|
||||
wire_iface_t ble_iface = {0};
|
||||
protob_io_t protob_usb_iface = {0};
|
||||
protob_io_t protob_ble_iface = {0};
|
||||
|
||||
redraw_wait_screen();
|
||||
|
||||
@ -43,31 +53,89 @@ workflow_result_t workflow_host_control(const vendor_header *const vhdr,
|
||||
usb_iface_init(&usb_iface,
|
||||
(vhdr == NULL && hdr == NULL) ? sectrue : secfalse);
|
||||
|
||||
ble_iface_init(&ble_iface);
|
||||
|
||||
protob_init(&protob_usb_iface, &usb_iface);
|
||||
protob_init(&protob_ble_iface, &ble_iface);
|
||||
|
||||
workflow_result_t result = WF_ERROR_FATAL;
|
||||
|
||||
for (;;) {
|
||||
uint16_t ifaces[1] = {protob_get_iface_flag(&protob_usb_iface) | MODE_READ};
|
||||
uint16_t ifaces[] = {
|
||||
protob_get_iface_flag(&protob_usb_iface) | MODE_READ,
|
||||
#ifdef USE_BLE
|
||||
protob_get_iface_flag(&protob_ble_iface) | MODE_READ,
|
||||
IFACE_BLE_EVENT,
|
||||
#ifdef USE_BUTTON
|
||||
IFACE_BUTTON,
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
poll_event_t e = {0};
|
||||
|
||||
uint8_t i = poll_events(ifaces, 1, &e, 100);
|
||||
int16_t i = poll_events(ifaces, ARRAY_LENGTH(ifaces), &e, 100);
|
||||
|
||||
if (i < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t msg_id = 0;
|
||||
protob_io_t *active_iface = NULL;
|
||||
|
||||
switch (e.type) {
|
||||
case EVENT_USB_CAN_READ:
|
||||
if (i == protob_get_iface_flag(&protob_usb_iface) &&
|
||||
sectrue == protob_get_msg_header(&protob_usb_iface, &msg_id)) {
|
||||
active_iface = &protob_usb_iface;
|
||||
} else {
|
||||
if (i < IFACE_USB_MAX) {
|
||||
switch (e.event.usb_data_event) {
|
||||
case EVENT_USB_CAN_READ:
|
||||
if (i == protob_get_iface_flag(&protob_usb_iface) &&
|
||||
sectrue == protob_get_msg_header(&protob_usb_iface, &msg_id)) {
|
||||
active_iface = &protob_usb_iface;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case EVENT_NONE:
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#ifdef USE_BLE
|
||||
if (i == IFACE_BLE) {
|
||||
switch (e.event.ble_data_event) {
|
||||
case EVENT_BLE_CAN_READ:
|
||||
if (i == protob_get_iface_flag(&protob_ble_iface) &&
|
||||
sectrue == protob_get_msg_header(&protob_ble_iface, &msg_id)) {
|
||||
active_iface = &protob_ble_iface;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (i == IFACE_BLE_EVENT) {
|
||||
switch (e.event.ble_event.type) {
|
||||
case BLE_PAIRING_REQUEST:
|
||||
workflow_ble_pairing_request(e.event.ble_event.data);
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef USE_BUTTON
|
||||
if (i == IFACE_BUTTON) {
|
||||
switch (e.event.button_event.type) {
|
||||
case (BTN_EVT_DOWN >> 24):
|
||||
ble_iface_start_pairing();
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (active_iface == NULL) {
|
||||
continue;
|
||||
;
|
||||
}
|
||||
|
||||
switch (msg_id) {
|
||||
|
@ -66,3 +66,7 @@ workflow_result_t workflow_host_control(const vendor_header *const vhdr,
|
||||
|
||||
workflow_result_t workflow_auto_update(const vendor_header *const vhdr,
|
||||
const image_header *const hdr);
|
||||
|
||||
#ifdef USE_BLE
|
||||
workflow_result_t workflow_ble_pairing_request(const uint8_t *data);
|
||||
#endif
|
||||
|
@ -27,3 +27,5 @@ void bld_continue_label(uint16_t bg_color);
|
||||
void screen_boot(bool warning, const char* vendor_str, size_t vendor_str_len,
|
||||
uint32_t version, const void* vendor_img,
|
||||
size_t vendor_img_len, int wait);
|
||||
|
||||
uint32_t screen_confirm_pairing(const uint8_t* code);
|
||||
|
@ -144,3 +144,10 @@ extern "C" fn screen_wipe_success() {
|
||||
extern "C" fn screen_wipe_fail() {
|
||||
ModelUI::screen_wipe_fail()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_confirm_pairing(code: *const cty::c_char) -> u32 {
|
||||
let code = unwrap!(unsafe { from_c_array(code, 6) });
|
||||
|
||||
ModelUI::screen_confirm_pairing(code)
|
||||
}
|
||||
|
@ -439,4 +439,18 @@ impl BootloaderUI for UIBolt {
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn screen_confirm_pairing(code: &str) -> u32 {
|
||||
let title = Label::centered("Pair device".into(), TEXT_NORMAL);
|
||||
|
||||
let msg = Label::centered(code.into(), TEXT_NORMAL);
|
||||
|
||||
let right = Button::with_text("CONFIRM".into()).styled(button_confirm());
|
||||
let left = Button::with_text("REJECT".into()).styled(button_bld());
|
||||
|
||||
let mut frame = Confirm::new(BLD_BG, left, right, ConfirmTitle::Text(title), msg);
|
||||
|
||||
run(&mut frame)
|
||||
}
|
||||
}
|
||||
|
@ -48,4 +48,7 @@ pub trait BootloaderUI {
|
||||
vendor_img: &'static [u8],
|
||||
wait: i32,
|
||||
);
|
||||
|
||||
#[cfg(feature = "ble")]
|
||||
fn screen_confirm_pairing(code: &str) -> u32;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user