|
|
|
@ -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;
|
|
|
|
|