feat(core/bootloader): dynamically decide to listen either USB or BLE

[no changelog]
tychovrahe/bluetooth/unification2
tychovrahe 1 year ago
parent 4ce0df6fc4
commit 9305ef7b25

@ -82,7 +82,8 @@ typedef enum {
CONTINUE = 0,
RETURN = 1,
SHUTDOWN = 2,
} usb_result_t;
NO_RESULT = -1,
} comm_result_t;
static void usb_init_all(secbool usb21_landing) {
usb_dev_info_t dev_info = {
@ -124,15 +125,6 @@ static void usb_init_all(secbool usb21_landing) {
usb_start();
}
void start_comm(secbool usb21_landing) {
// if both are NULL, we don't have a firmware installed
// let's show a webusb landing page in this case
usb_init_all(usb21_landing);
#ifdef USE_BLE
start_advertising();
#endif
}
void stop_comm(void) {
hal_delay(100);
usb_stop();
@ -142,64 +134,138 @@ void stop_comm(void) {
#endif
}
static usb_result_t bootloader_comm_loop(const vendor_header *const vhdr,
static comm_result_t process_common_messages(uint8_t iface, uint8_t *buf,
const vendor_header *const vhdr,
const image_header *const hdr) {
uint16_t msg_id;
uint32_t msg_size;
uint32_t response;
int32_t upload_response;
if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) {
// invalid header -> discard
return NO_RESULT;
}
switch (msg_id) {
case 0: // Initialize
process_msg_Initialize(iface, msg_size, buf, vhdr, hdr);
break;
case 1: // Ping
process_msg_Ping(iface, msg_size, buf);
break;
case 5: // WipeDevice
response = ui_screen_wipe_confirm();
if (INPUT_CANCEL == response) {
send_user_abort(iface, "Wipe cancelled");
stop_comm();
return RETURN;
}
ui_screen_wipe();
upload_response = process_msg_WipeDevice(iface, msg_size, buf);
if (upload_response < 0) { // error
screen_wipe_fail();
stop_comm();
return SHUTDOWN;
} else { // success
screen_wipe_success();
stop_comm();
return SHUTDOWN;
}
break;
case 6: // FirmwareErase
process_msg_FirmwareErase(iface, msg_size, buf);
break;
case 7: // FirmwareUpload
upload_response = process_msg_FirmwareUpload(iface, msg_size, buf);
if (upload_response < 0 &&
upload_response !=
UPLOAD_ERR_USER_ABORT) { // error, but not user abort
ui_screen_fail();
stop_comm();
return SHUTDOWN;
} else if (upload_response == UPLOAD_ERR_USER_ABORT) {
stop_comm();
return RETURN;
} else if (upload_response == 0) { // last chunk received
ui_screen_install_progress_upload(1000);
ui_screen_done(4, sectrue);
ui_screen_done(3, secfalse);
hal_delay(1000);
ui_screen_done(2, secfalse);
hal_delay(1000);
ui_screen_done(1, secfalse);
hal_delay(1000);
stop_comm();
ui_screen_boot_empty(true);
return CONTINUE;
}
break;
case 55: // GetFeatures
process_msg_GetFeatures(iface, msg_size, buf, vhdr, hdr);
break;
default:
process_msg_unknown(iface, msg_size, buf);
break;
}
return NO_RESULT;
}
static comm_result_t bootloader_usb_loop(const vendor_header *const vhdr,
const image_header *const hdr) {
start_comm((vhdr == NULL && hdr == NULL) ? sectrue : secfalse);
uint8_t buf[USB_PACKET_SIZE];
uint8_t buf_usb[USB_PACKET_SIZE];
#ifdef USE_BLE
uint8_t ble_buf[BLE_PACKET_SIZE];
for (;;) {
#ifdef TREZOR_EMULATOR
emulator_poll_events();
#endif
uint8_t *buf = NULL;
int r = usb_webusb_read_blocking(USB_IFACE_NUM, buf, USB_PACKET_SIZE,
USB_TIMEOUT);
if (r != USB_PACKET_SIZE) {
continue;
}
comm_result_t res = process_common_messages(USB_IFACE_NUM, buf, vhdr, hdr);
if (res != NO_RESULT) {
return res;
}
}
}
#ifdef USE_BLE
static comm_result_t bootloader_ble_loop(const vendor_header *const vhdr,
const image_header *const hdr) {
start_advertising();
uint8_t buf[BLE_PACKET_SIZE];
uint8_t active_iface = 0;
int r = 0;
for (;;) {
for (;;) {
#ifdef TREZOR_EMULATOR
emulator_poll_events();
#endif
r = usb_webusb_read_blocking(USB_IFACE_NUM, buf_usb, USB_PACKET_SIZE, 20);
if (r == USB_PACKET_SIZE) {
active_iface = USB_IFACE_NUM;
buf = buf_usb;
break;
}
#ifdef USE_BLE
r = ble_ext_comm_receive(ble_buf, sizeof(ble_buf));
r = ble_ext_comm_receive(buf, sizeof(buf));
if (r == BLE_PACKET_SIZE) {
active_iface = BLE_EXT_IFACE_NUM;
buf = ble_buf;
break;
}
r = ble_int_comm_receive(ble_buf, sizeof(ble_buf));
r = ble_int_comm_receive(buf, sizeof(buf));
if (r != 0) {
active_iface = BLE_INT_IFACE_NUM;
buf = ble_buf;
break;
}
ble_event_poll();
#endif
}
#ifdef USE_BLE
if (active_iface == BLE_INT_IFACE_NUM) {
for (;;) {
bool next = false;
if (r == 0) {
if (active_iface == BLE_INT_IFACE_NUM) {
r = ble_int_comm_receive(ble_buf, sizeof(ble_buf));
r = ble_int_comm_receive(buf, sizeof(buf));
if (r == 0) {
continue;
}
} else {
// unknown interface
return CONTINUE;
if (r == 0) {
continue;
}
}
@ -214,7 +280,7 @@ static usb_result_t bootloader_comm_loop(const vendor_header *const vhdr,
}
switch (msg_id) {
case MessageType_MessageType_PairingRequest: // pairing request
response = process_msg_Pairing(active_iface, msg_size, ble_buf);
response = process_msg_Pairing(active_iface, msg_size, buf);
if (response != INPUT_CONFIRM) {
stop_comm();
return RETURN;
@ -224,7 +290,7 @@ static usb_result_t bootloader_comm_loop(const vendor_header *const vhdr,
break;
case MessageType_MessageType_RepairRequest: // repairing request
response = process_msg_Repair(active_iface, msg_size, ble_buf);
response = process_msg_Repair(active_iface, msg_size, buf);
if (response != INPUT_CONFIRM) {
stop_comm();
return RETURN;
@ -233,7 +299,7 @@ static usb_result_t bootloader_comm_loop(const vendor_header *const vhdr,
// todo - screen connect or timeout?
break;
default:
process_msg_unknown(active_iface, msg_size, ble_buf);
process_msg_unknown(active_iface, msg_size, buf);
break;
}
if (next) {
@ -241,113 +307,58 @@ static usb_result_t bootloader_comm_loop(const vendor_header *const vhdr,
}
}
}
#endif
if (active_iface == USB_IFACE_NUM || active_iface == BLE_EXT_IFACE_NUM) {
if (active_iface == BLE_EXT_IFACE_NUM) {
for (;;) {
#ifdef TREZOR_EMULATOR
emulator_poll_events();
#endif
if (r == 0) {
if (active_iface == USB_IFACE_NUM) {
r = usb_webusb_read_blocking(active_iface, buf_usb, USB_PACKET_SIZE,
USB_TIMEOUT);
if (r != USB_PACKET_SIZE) {
continue;
}
}
#ifdef USE_BLE
else if (active_iface == BLE_EXT_IFACE_NUM) {
r = ble_ext_comm_receive(ble_buf, sizeof(ble_buf));
r = ble_ext_comm_receive(buf, sizeof(buf));
if (r != BLE_PACKET_SIZE) {
continue;
}
}
#endif
else {
// unknown interface
return CONTINUE;
if (r != BLE_PACKET_SIZE) {
continue;
}
}
r = 0;
uint16_t msg_id;
uint32_t msg_size;
uint32_t response;
int32_t upload_response;
if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) {
// invalid header -> discard
continue;
}
switch (msg_id) {
case 0: // Initialize
process_msg_Initialize(active_iface, msg_size, buf, vhdr, hdr);
break;
case 1: // Ping
process_msg_Ping(active_iface, msg_size, buf);
break;
case 5: // WipeDevice
response = ui_screen_wipe_confirm();
if (INPUT_CANCEL == response) {
send_user_abort(active_iface, "Wipe cancelled");
stop_comm();
return RETURN;
}
ui_screen_wipe();
upload_response =
process_msg_WipeDevice(active_iface, msg_size, buf);
if (upload_response < 0) { // error
screen_wipe_fail();
stop_comm();
return SHUTDOWN;
} else { // success
screen_wipe_success();
stop_comm();
return SHUTDOWN;
}
break;
case 6: // FirmwareErase
process_msg_FirmwareErase(active_iface, msg_size, buf);
break;
case 7: // FirmwareUpload
upload_response =
process_msg_FirmwareUpload(active_iface, msg_size, buf);
if (upload_response < 0 &&
upload_response !=
UPLOAD_ERR_USER_ABORT) { // error, but not user abort
ui_screen_fail();
stop_comm();
return SHUTDOWN;
} else if (upload_response == UPLOAD_ERR_USER_ABORT) {
stop_comm();
return RETURN;
} else if (upload_response == 0) { // last chunk received
ui_screen_install_progress_upload(1000);
ui_screen_done(4, sectrue);
ui_screen_done(3, secfalse);
hal_delay(1000);
ui_screen_done(2, secfalse);
hal_delay(1000);
ui_screen_done(1, secfalse);
hal_delay(1000);
stop_comm();
ui_screen_boot_empty(true);
return CONTINUE;
}
break;
case 55: // GetFeatures
process_msg_GetFeatures(active_iface, msg_size, buf, vhdr, hdr);
break;
default:
process_msg_unknown(active_iface, msg_size, buf);
break;
comm_result_t res =
process_common_messages(active_iface, buf, vhdr, hdr);
if (res != NO_RESULT) {
return res;
}
}
}
}
}
#endif
static comm_result_t bootloader_comm_select(const vendor_header *const vhdr,
const image_header *const hdr) {
// if both are NULL, we don't have a firmware installed
// let's show a webusb landing page in this case
usb_init_all((vhdr == NULL && hdr == NULL) ? sectrue : secfalse);
#ifdef USE_BLE
bool usb = false;
for (int i = 0; i < 2000; i++) {
hal_delay(1);
if (usb_configured_now() == sectrue) {
usb = true;
break;
}
}
if (usb) {
return bootloader_usb_loop(vhdr, hdr);
} else {
usb_stop();
usb_deinit();
return bootloader_ble_loop(vhdr, hdr);
}
#else
return bootloader_usb_loop(vhdr, hdr);
#endif
}
secbool check_vendor_header_keys(const vendor_header *const vhdr) {
return check_vendor_header_sig(vhdr, BOOTLOADER_KEY_M, BOOTLOADER_KEY_N,
@ -539,7 +550,7 @@ int bootloader_main(void) {
NULL);
// and start the usb loop
if (bootloader_comm_loop(NULL, NULL) != CONTINUE) {
if (bootloader_comm_select(NULL, NULL) != CONTINUE) {
return 1;
}
}
@ -598,7 +609,7 @@ int bootloader_main(void) {
break;
case SCREEN_WAIT_FOR_HOST:
screen_connect();
switch (bootloader_comm_loop(&vhdr, hdr)) {
switch (bootloader_comm_select(&vhdr, hdr)) {
case CONTINUE:
continue_to_firmware = true;
break;

@ -187,6 +187,15 @@ secbool usb_configured(void) {
return secfalse;
}
secbool usb_configured_now(void) {
const USBD_HandleTypeDef *pdev = &usb_dev_handle;
if (pdev->dev_state == USBD_STATE_SUSPENDED &&
pdev->dev_old_state == USBD_STATE_CONFIGURED) {
return sectrue;
}
return secfalse;
}
/*
* Utility functions for USB interfaces
*/

@ -144,5 +144,6 @@ void usb_deinit(void);
void usb_start(void);
void usb_stop(void);
secbool usb_configured(void);
secbool usb_configured_now(void);
#endif

Loading…
Cancel
Save