mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-30 18:38:27 +00:00
STM
This commit is contained in:
parent
45db7ae1c4
commit
a8ae9496cb
@ -39,6 +39,7 @@ message Failure {
|
||||
Failure_PinMismatch = 12;
|
||||
Failure_WipeCodeMismatch = 13;
|
||||
Failure_InvalidSession = 14;
|
||||
Failure_DeviceIsBusy = 15;
|
||||
Failure_FirmwareError = 99;
|
||||
}
|
||||
}
|
||||
|
@ -403,6 +403,9 @@ upload: ## upload firmware using trezorctl
|
||||
upload_prodtest: ## upload prodtest using trezorctl
|
||||
trezorctl firmware_update -s -f $(PRODTEST_BUILD_DIR)/prodtest.bin
|
||||
|
||||
upload_ble: ## upload ble firmware using trezorctl
|
||||
trezorctl ble update $(BLE_FIRMWARE_BUILD_DIR)/ble_firmware.zip
|
||||
|
||||
coverage: ## generate coverage report
|
||||
./tools/coverage-report
|
||||
|
||||
|
@ -20,7 +20,7 @@ if TREZOR_MODEL in ('1', ):
|
||||
)
|
||||
Return()
|
||||
|
||||
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga"]
|
||||
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga", "ble"]
|
||||
|
||||
CCFLAGS_MOD = ''
|
||||
CPPPATH_MOD = []
|
||||
@ -38,9 +38,9 @@ if TREZOR_MODEL in ('R', ):
|
||||
FONT_BIG=None
|
||||
elif TREZOR_MODEL in ('T', 'T3W1', 'DISC1'):
|
||||
FONT_NORMAL='Font_TTHoves_Regular_21'
|
||||
FONT_DEMIBOLD=None
|
||||
FONT_DEMIBOLD='Font_TTHoves_Regular_21'
|
||||
FONT_BOLD='Font_TTHoves_Bold_17'
|
||||
FONT_MONO=None
|
||||
FONT_MONO='Font_TTHoves_Regular_21'
|
||||
FONT_BIG=None
|
||||
|
||||
# modtrezorcrypto
|
||||
@ -87,6 +87,7 @@ SOURCE_MOD += [
|
||||
'embed/lib/fonts/fonts.c',
|
||||
'embed/lib/fonts/font_bitmap.c',
|
||||
'embed/lib/image.c',
|
||||
'embed/lib/protob_helpers.c',
|
||||
'embed/extmod/modtrezorcrypto/rand.c',
|
||||
'vendor/micropython/lib/uzlib/adler32.c',
|
||||
'vendor/micropython/lib/uzlib/crc32.c',
|
||||
@ -150,7 +151,6 @@ env.Replace(
|
||||
CPPPATH=[
|
||||
'embed/rust',
|
||||
'embed/bootloader',
|
||||
'embed/bootloader/nanopb',
|
||||
'embed/bootloader/protob',
|
||||
'embed/lib',
|
||||
'embed/models',
|
||||
|
@ -21,7 +21,7 @@ FEATURE_FLAGS = {
|
||||
"SYSTEM_VIEW": False,
|
||||
}
|
||||
|
||||
FEATURES_WANTED = ["input", "sbu", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga"]
|
||||
FEATURES_WANTED = ["input", "sbu", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga", "ble"]
|
||||
if DISABLE_OPTIGA and PYOPT == '0':
|
||||
FEATURES_WANTED.remove("optiga")
|
||||
|
||||
@ -441,6 +441,7 @@ env.Replace(
|
||||
'embed/firmware',
|
||||
'embed/lib',
|
||||
'embed/models',
|
||||
'embed/firmware/ble',
|
||||
'embed/trezorhal',
|
||||
'embed/extmod/modtrezorui',
|
||||
'vendor/micropython',
|
||||
|
@ -526,6 +526,7 @@ env.Replace(
|
||||
'embed/unix',
|
||||
'embed/trezorhal',
|
||||
'embed/trezorhal/unix',
|
||||
'embed/trezorhal/unix/ble',
|
||||
'embed/extmod/modtrezorui',
|
||||
'vendor/micropython',
|
||||
'vendor/micropython/ports/unix',
|
||||
|
@ -69,10 +69,15 @@ static void format_ver(const char *format, uint32_t version, char *buffer,
|
||||
// boot UI
|
||||
|
||||
static uint16_t boot_background;
|
||||
static uint8_t iface;
|
||||
static bool initial_setup = true;
|
||||
|
||||
void ui_set_initial_setup(bool initial) { initial_setup = initial; }
|
||||
|
||||
void ui_set_interface(uint8_t iface_num) { iface = iface_num; }
|
||||
|
||||
void ui_screen_connect(void) { screen_connect(initial_setup, iface); }
|
||||
|
||||
void ui_screen_boot(const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
const int show_string = ((vhdr->vtrust & VTRUST_STRING) == 0);
|
||||
|
@ -41,6 +41,7 @@ void ui_screen_boot_click(void);
|
||||
void ui_click(void);
|
||||
|
||||
void ui_screen_welcome(void);
|
||||
void ui_screen_connect(void);
|
||||
|
||||
uint32_t ui_screen_intro(const vendor_header* const vhdr,
|
||||
const image_header* const hdr, bool fw_ok);
|
||||
@ -67,6 +68,7 @@ void ui_screen_install_restricted(void);
|
||||
void ui_fadein(void);
|
||||
void ui_fadeout(void);
|
||||
void ui_set_initial_setup(bool initial);
|
||||
void ui_set_interface(uint8_t iface_num);
|
||||
|
||||
void ui_screen_boot_empty(bool fading);
|
||||
|
||||
|
@ -51,12 +51,20 @@
|
||||
#ifdef USE_RGB_LED
|
||||
#include "rgb_led.h"
|
||||
#endif
|
||||
#ifdef USE_BLE
|
||||
#include "ble/messages.h"
|
||||
#include "ble/state.h"
|
||||
#include "ble_hal.h"
|
||||
#endif
|
||||
|
||||
#include "model.h"
|
||||
#include "usb.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "bootui.h"
|
||||
#include "messages.h"
|
||||
#include "messages.pb.h"
|
||||
#include "protob_helpers.h"
|
||||
#include "rust_ui.h"
|
||||
#include "unit_variant.h"
|
||||
|
||||
@ -75,7 +83,8 @@ typedef enum {
|
||||
SHUTDOWN = 0,
|
||||
CONTINUE_TO_FIRMWARE = 0xAABBCCDD,
|
||||
RETURN_TO_MENU = 0x55667788,
|
||||
} usb_result_t;
|
||||
NO_RESULT = -1,
|
||||
} comm_result_t;
|
||||
|
||||
volatile secbool dont_optimize_out_true = sectrue;
|
||||
void failed_jump_to_firmware(void);
|
||||
@ -121,12 +130,111 @@ static void usb_init_all(secbool usb21_landing) {
|
||||
usb_start();
|
||||
}
|
||||
|
||||
static usb_result_t bootloader_usb_loop(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);
|
||||
void stop_comm(void) {
|
||||
hal_delay(100);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
#ifdef USE_BLE
|
||||
stop_advertising();
|
||||
#endif
|
||||
}
|
||||
|
||||
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 MessageType_MessageType_Initialize:
|
||||
process_msg_Initialize(iface, msg_size, buf, vhdr, hdr);
|
||||
break;
|
||||
case MessageType_MessageType_Ping:
|
||||
process_msg_Ping(iface, msg_size, buf);
|
||||
break;
|
||||
case MessageType_MessageType_WipeDevice:
|
||||
response = ui_screen_wipe_confirm();
|
||||
if (INPUT_CANCEL == response) {
|
||||
send_user_abort(iface, "Wipe cancelled");
|
||||
stop_comm();
|
||||
return RETURN_TO_MENU;
|
||||
}
|
||||
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 MessageType_MessageType_FirmwareErase:
|
||||
process_msg_FirmwareErase(iface, msg_size, buf);
|
||||
break;
|
||||
case MessageType_MessageType_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
|
||||
if (upload_response == UPLOAD_ERR_BOOTLOADER_LOCKED) {
|
||||
ui_screen_install_restricted();
|
||||
} else {
|
||||
ui_screen_fail();
|
||||
}
|
||||
stop_comm();
|
||||
return SHUTDOWN;
|
||||
} else if (upload_response == UPLOAD_ERR_USER_ABORT) {
|
||||
stop_comm();
|
||||
return RETURN_TO_MENU;
|
||||
} 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_TO_FIRMWARE;
|
||||
}
|
||||
break;
|
||||
case MessageType_MessageType_GetFeatures:
|
||||
process_msg_GetFeatures(iface, msg_size, buf, vhdr, hdr);
|
||||
break;
|
||||
#ifdef USE_OPTIGA
|
||||
case MessageType_MessageType_UnlockBootloader:
|
||||
response = ui_screen_unlock_bootloader_confirm();
|
||||
if (INPUT_CANCEL == response) {
|
||||
send_user_abort(USB_IFACE_NUM, "Bootloader unlock cancelled");
|
||||
stop_comm();
|
||||
return RETURN_TO_MENU;
|
||||
}
|
||||
process_msg_UnlockBootloader(USB_IFACE_NUM, msg_size, buf);
|
||||
screen_unlock_bootloader_success();
|
||||
stop_comm();
|
||||
return SHUTDOWN;
|
||||
break;
|
||||
#endif
|
||||
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) {
|
||||
uint8_t buf[USB_PACKET_SIZE];
|
||||
|
||||
for (;;) {
|
||||
@ -138,107 +246,168 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
if (r != USB_PACKET_SIZE) {
|
||||
continue;
|
||||
}
|
||||
uint16_t msg_id;
|
||||
uint32_t msg_size;
|
||||
uint32_t response;
|
||||
if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) {
|
||||
// invalid header -> discard
|
||||
continue;
|
||||
}
|
||||
switch (msg_id) {
|
||||
case MessageType_MessageType_Initialize:
|
||||
process_msg_Initialize(USB_IFACE_NUM, msg_size, buf, vhdr, hdr);
|
||||
break;
|
||||
case MessageType_MessageType_Ping:
|
||||
process_msg_Ping(USB_IFACE_NUM, msg_size, buf);
|
||||
break;
|
||||
case MessageType_MessageType_WipeDevice:
|
||||
response = ui_screen_wipe_confirm();
|
||||
if (INPUT_CANCEL == response) {
|
||||
send_user_abort(USB_IFACE_NUM, "Wipe cancelled");
|
||||
hal_delay(100);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return RETURN_TO_MENU;
|
||||
}
|
||||
ui_screen_wipe();
|
||||
r = process_msg_WipeDevice(USB_IFACE_NUM, msg_size, buf);
|
||||
if (r < 0) { // error
|
||||
screen_wipe_fail();
|
||||
hal_delay(100);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return SHUTDOWN;
|
||||
} else { // success
|
||||
screen_wipe_success();
|
||||
hal_delay(100);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return SHUTDOWN;
|
||||
}
|
||||
break;
|
||||
case MessageType_MessageType_FirmwareErase:
|
||||
process_msg_FirmwareErase(USB_IFACE_NUM, msg_size, buf);
|
||||
break;
|
||||
case MessageType_MessageType_FirmwareUpload:
|
||||
r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf);
|
||||
if (r < 0 && r != UPLOAD_ERR_USER_ABORT) { // error, but not user abort
|
||||
if (r == UPLOAD_ERR_BOOTLOADER_LOCKED) {
|
||||
ui_screen_install_restricted();
|
||||
} else {
|
||||
ui_screen_fail();
|
||||
}
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return SHUTDOWN;
|
||||
} else if (r == UPLOAD_ERR_USER_ABORT) {
|
||||
hal_delay(100);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return RETURN_TO_MENU;
|
||||
} else if (r == 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);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
ui_screen_boot_empty(true);
|
||||
return CONTINUE_TO_FIRMWARE;
|
||||
}
|
||||
break;
|
||||
case MessageType_MessageType_GetFeatures:
|
||||
process_msg_GetFeatures(USB_IFACE_NUM, msg_size, buf, vhdr, hdr);
|
||||
break;
|
||||
#ifdef USE_OPTIGA
|
||||
case MessageType_MessageType_UnlockBootloader:
|
||||
response = ui_screen_unlock_bootloader_confirm();
|
||||
if (INPUT_CANCEL == response) {
|
||||
send_user_abort(USB_IFACE_NUM, "Bootloader unlock cancelled");
|
||||
hal_delay(100);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return RETURN_TO_MENU;
|
||||
}
|
||||
process_msg_UnlockBootloader(USB_IFACE_NUM, msg_size, buf);
|
||||
screen_unlock_bootloader_success();
|
||||
hal_delay(100);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return SHUTDOWN;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
process_msg_unknown(USB_IFACE_NUM, msg_size, buf);
|
||||
break;
|
||||
|
||||
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) {
|
||||
ble_comm_start();
|
||||
if (!ble_initialize() || !ble_initialized()) {
|
||||
error_shutdown("INTERNAL ERROR", "BLE NOT AVAILABLE");
|
||||
}
|
||||
|
||||
auto_start_advertising();
|
||||
|
||||
uint8_t buf[BLE_PACKET_SIZE];
|
||||
|
||||
uint8_t active_iface = 0;
|
||||
int r = 0;
|
||||
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
if ((button_read() & (BTN_EVT_DOWN | BTN_POWER)) ==
|
||||
(BTN_EVT_DOWN | BTN_POWER)) {
|
||||
start_advertising(false);
|
||||
}
|
||||
|
||||
r = ble_ext_comm_receive(buf, sizeof(buf));
|
||||
|
||||
if (r == BLE_PACKET_SIZE) {
|
||||
active_iface = BLE_EXT_IFACE_NUM;
|
||||
break;
|
||||
}
|
||||
|
||||
r = ble_int_comm_receive(buf, sizeof(buf));
|
||||
if (r != 0) {
|
||||
active_iface = BLE_INT_IFACE_NUM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (active_iface == BLE_INT_IFACE_NUM) {
|
||||
for (;;) {
|
||||
bool next = false;
|
||||
if (r == 0) {
|
||||
r = ble_int_comm_receive(buf, sizeof(buf));
|
||||
|
||||
if (r == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
uint16_t msg_id;
|
||||
uint32_t msg_size;
|
||||
uint32_t response;
|
||||
if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) {
|
||||
// invalid header -> discard
|
||||
continue;
|
||||
}
|
||||
switch (msg_id) {
|
||||
case MessageType_MessageType_ComparisonRequest: // pairing request
|
||||
response =
|
||||
process_msg_ComparisonRequest(active_iface, msg_size, buf);
|
||||
if (response != INPUT_CONFIRM) {
|
||||
stop_comm();
|
||||
return RETURN_TO_MENU;
|
||||
}
|
||||
ui_screen_connect();
|
||||
next = true;
|
||||
|
||||
break;
|
||||
case MessageType_MessageType_PairingRequest: // pairing request
|
||||
response = process_msg_Pairing(active_iface, msg_size, buf);
|
||||
if (response != INPUT_CONFIRM) {
|
||||
stop_comm();
|
||||
return RETURN_TO_MENU;
|
||||
}
|
||||
ui_screen_connect();
|
||||
next = true;
|
||||
|
||||
break;
|
||||
case MessageType_MessageType_RepairRequest: // repairing request
|
||||
response = process_msg_Repair(active_iface, msg_size, buf);
|
||||
if (response != INPUT_CONFIRM) {
|
||||
stop_comm();
|
||||
return RETURN_TO_MENU;
|
||||
}
|
||||
ui_screen_connect();
|
||||
break;
|
||||
default:
|
||||
process_msg_unknown(active_iface, msg_size, buf);
|
||||
break;
|
||||
}
|
||||
if (next) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (active_iface == BLE_EXT_IFACE_NUM) {
|
||||
for (;;) {
|
||||
if (r == 0) {
|
||||
r = ble_ext_comm_receive(buf, sizeof(buf));
|
||||
|
||||
if (r != BLE_PACKET_SIZE) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
r = 0;
|
||||
|
||||
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,
|
||||
bool show_connect_screen) {
|
||||
// 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_us(1000);
|
||||
if (usb_configured_now() == sectrue) {
|
||||
usb = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (usb) {
|
||||
return bootloader_usb_loop(vhdr, hdr);
|
||||
} else {
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
ui_set_interface(1);
|
||||
if (show_connect_screen) {
|
||||
ui_screen_connect();
|
||||
}
|
||||
return bootloader_ble_loop(vhdr, hdr);
|
||||
}
|
||||
#else
|
||||
return bootloader_usb_loop(vhdr, hdr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static secbool check_vendor_header_lock(const vendor_header *const vhdr) {
|
||||
uint8_t lock[FLASH_OTP_BLOCK_SIZE];
|
||||
ensure(flash_otp_read(FLASH_OTP_BLOCK_VENDOR_HEADER_LOCK, 0, lock,
|
||||
@ -457,6 +626,9 @@ int bootloader_main(void) {
|
||||
#ifdef USE_RGB_LED
|
||||
rgb_led_init();
|
||||
#endif
|
||||
#ifdef USE_BLE
|
||||
ble_comm_init();
|
||||
#endif
|
||||
|
||||
unit_variant_init();
|
||||
|
||||
@ -554,7 +726,8 @@ int bootloader_main(void) {
|
||||
ui_screen_welcome();
|
||||
|
||||
// and start the usb loop
|
||||
switch (bootloader_usb_loop(NULL, NULL)) {
|
||||
ui_set_interface(0);
|
||||
switch (bootloader_comm_select(NULL, NULL, false)) {
|
||||
case CONTINUE_TO_FIRMWARE:
|
||||
continue_to_firmware = sectrue;
|
||||
continue_to_firmware_backup = sectrue;
|
||||
@ -610,8 +783,9 @@ int bootloader_main(void) {
|
||||
}
|
||||
break;
|
||||
case SCREEN_WAIT_FOR_HOST:
|
||||
screen_connect(auto_upgrade == sectrue);
|
||||
switch (bootloader_usb_loop(&vhdr, hdr)) {
|
||||
screen_connect(auto_upgrade == sectrue, 0);
|
||||
ui_set_interface(1);
|
||||
switch (bootloader_comm_select(&vhdr, hdr, true)) {
|
||||
case CONTINUE_TO_FIRMWARE:
|
||||
continue_to_firmware = sectrue;
|
||||
continue_to_firmware_backup = sectrue;
|
||||
@ -646,6 +820,10 @@ int bootloader_main(void) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BLE
|
||||
ble_stop_all_comm();
|
||||
#endif
|
||||
|
||||
ensure(dont_optimize_out_true * (firmware_present == firmware_present_backup),
|
||||
NULL);
|
||||
if (sectrue == firmware_present) {
|
||||
|
@ -25,6 +25,12 @@
|
||||
#include "messages.pb.h"
|
||||
|
||||
#include "boot_internal.h"
|
||||
#include TREZOR_BOARD
|
||||
|
||||
#ifdef USE_BLE
|
||||
#include "ble/ble.h"
|
||||
#include "ble_hal.h"
|
||||
#endif
|
||||
#include "common.h"
|
||||
#include "flash.h"
|
||||
#include "image.h"
|
||||
@ -36,6 +42,7 @@
|
||||
|
||||
#include "bootui.h"
|
||||
#include "messages.h"
|
||||
#include "protob_helpers.h"
|
||||
#include "rust_ui.h"
|
||||
|
||||
#include "memzero.h"
|
||||
@ -49,30 +56,9 @@
|
||||
#include "secret.h"
|
||||
#endif
|
||||
|
||||
#define MSG_HEADER1_LEN 9
|
||||
#define MSG_HEADER2_LEN 1
|
||||
|
||||
secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id,
|
||||
uint32_t *msg_size) {
|
||||
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') {
|
||||
return secfalse;
|
||||
}
|
||||
*msg_id = (buf[3] << 8) + buf[4];
|
||||
*msg_size = (buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8];
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t iface_num;
|
||||
uint8_t packet_index;
|
||||
uint8_t packet_pos;
|
||||
uint8_t buf[USB_PACKET_SIZE];
|
||||
} usb_write_state;
|
||||
|
||||
/* we don't use secbool/sectrue/secfalse here as it is a nanopb api */
|
||||
static bool _usb_write(pb_ostream_t *stream, const pb_byte_t *buf,
|
||||
size_t count) {
|
||||
usb_write_state *state = (usb_write_state *)(stream->state);
|
||||
static bool _write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) {
|
||||
write_state *state = (write_state *)(stream->state);
|
||||
|
||||
size_t written = 0;
|
||||
// while we have data left
|
||||
@ -92,9 +78,20 @@ static bool _usb_write(pb_ostream_t *stream, const pb_byte_t *buf,
|
||||
USB_PACKET_SIZE - state->packet_pos);
|
||||
written += USB_PACKET_SIZE - state->packet_pos;
|
||||
// send packet
|
||||
int r = usb_webusb_write_blocking(state->iface_num, state->buf,
|
||||
USB_PACKET_SIZE, USB_TIMEOUT);
|
||||
ensure(sectrue * (r == USB_PACKET_SIZE), NULL);
|
||||
|
||||
if (state->iface_num == USB_IFACE_NUM) {
|
||||
int r = usb_webusb_write_blocking(state->iface_num, state->buf,
|
||||
USB_PACKET_SIZE, USB_TIMEOUT);
|
||||
ensure(sectrue * (r == USB_PACKET_SIZE), NULL);
|
||||
}
|
||||
#ifdef USE_BLE
|
||||
else if (state->iface_num == BLE_INT_IFACE_NUM) {
|
||||
ble_int_comm_send(state->buf, USB_PACKET_SIZE, INTERNAL_MESSAGE);
|
||||
} else if (state->iface_num == BLE_EXT_IFACE_NUM) {
|
||||
ble_int_comm_send(state->buf, USB_PACKET_SIZE, EXTERNAL_MESSAGE);
|
||||
}
|
||||
#endif
|
||||
|
||||
// prepare new packet
|
||||
state->packet_index++;
|
||||
memzero(state->buf, USB_PACKET_SIZE);
|
||||
@ -106,7 +103,7 @@ static bool _usb_write(pb_ostream_t *stream, const pb_byte_t *buf,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _usb_write_flush(usb_write_state *state) {
|
||||
static void _write_flush(write_state *state) {
|
||||
// if packet is not filled up completely
|
||||
if (state->packet_pos < USB_PACKET_SIZE) {
|
||||
// pad it with zeroes
|
||||
@ -114,94 +111,53 @@ static void _usb_write_flush(usb_write_state *state) {
|
||||
USB_PACKET_SIZE - state->packet_pos);
|
||||
}
|
||||
// send packet
|
||||
int r = usb_webusb_write_blocking(state->iface_num, state->buf,
|
||||
USB_PACKET_SIZE, USB_TIMEOUT);
|
||||
ensure(sectrue * (r == USB_PACKET_SIZE), NULL);
|
||||
if (state->iface_num == USB_IFACE_NUM) {
|
||||
int r = usb_webusb_write_blocking(state->iface_num, state->buf,
|
||||
USB_PACKET_SIZE, USB_TIMEOUT);
|
||||
ensure(sectrue * (r == USB_PACKET_SIZE), NULL);
|
||||
}
|
||||
#ifdef USE_BLE
|
||||
else if (state->iface_num == BLE_INT_IFACE_NUM) {
|
||||
ble_int_comm_send(state->buf, USB_PACKET_SIZE, INTERNAL_MESSAGE);
|
||||
} else if (state->iface_num == BLE_EXT_IFACE_NUM) {
|
||||
ble_int_comm_send(state->buf, USB_PACKET_SIZE, EXTERNAL_MESSAGE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static secbool _send_msg(uint8_t iface_num, uint16_t msg_id,
|
||||
const pb_msgdesc_t *fields, const void *msg) {
|
||||
// determine message size by serializing it into a dummy stream
|
||||
pb_ostream_t sizestream = {.callback = NULL,
|
||||
.state = NULL,
|
||||
.max_size = SIZE_MAX,
|
||||
.bytes_written = 0,
|
||||
.errmsg = NULL};
|
||||
if (false == pb_encode(&sizestream, fields, msg)) {
|
||||
return secfalse;
|
||||
}
|
||||
const uint32_t msg_size = sizestream.bytes_written;
|
||||
#define BLE_GAP_PASSKEY_LEN 6
|
||||
|
||||
usb_write_state state = {
|
||||
.iface_num = iface_num,
|
||||
.packet_index = 0,
|
||||
.packet_pos = MSG_HEADER1_LEN,
|
||||
.buf =
|
||||
{
|
||||
'?',
|
||||
'#',
|
||||
'#',
|
||||
(msg_id >> 8) & 0xFF,
|
||||
msg_id & 0xFF,
|
||||
(msg_size >> 24) & 0xFF,
|
||||
(msg_size >> 16) & 0xFF,
|
||||
(msg_size >> 8) & 0xFF,
|
||||
msg_size & 0xFF,
|
||||
},
|
||||
};
|
||||
/* we don't use secbool/sectrue/secfalse here as it is a nanopb api */
|
||||
static bool _write_authkey(pb_ostream_t *stream, const pb_field_iter_t *field,
|
||||
void *const *arg) {
|
||||
uint8_t *key = (uint8_t *)(*arg);
|
||||
if (!pb_encode_tag_for_field(stream, field)) return false;
|
||||
|
||||
pb_ostream_t stream = {.callback = &_usb_write,
|
||||
.state = &state,
|
||||
.max_size = SIZE_MAX,
|
||||
.bytes_written = 0,
|
||||
.errmsg = NULL};
|
||||
|
||||
if (false == pb_encode(&stream, fields, msg)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
_usb_write_flush(&state);
|
||||
|
||||
return sectrue;
|
||||
return pb_encode_string(stream, (uint8_t *)key, BLE_GAP_PASSKEY_LEN);
|
||||
}
|
||||
|
||||
#define MSG_SEND_INIT(TYPE) TYPE msg_send = TYPE##_init_default
|
||||
#define MSG_SEND_ASSIGN_REQUIRED_VALUE(FIELD, VALUE) \
|
||||
{ msg_send.FIELD = VALUE; }
|
||||
#define MSG_SEND_ASSIGN_VALUE(FIELD, VALUE) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
msg_send.FIELD = VALUE; \
|
||||
}
|
||||
#define MSG_SEND_ASSIGN_STRING(FIELD, VALUE) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
memzero(msg_send.FIELD, sizeof(msg_send.FIELD)); \
|
||||
strncpy(msg_send.FIELD, VALUE, sizeof(msg_send.FIELD) - 1); \
|
||||
}
|
||||
#define MSG_SEND_ASSIGN_STRING_LEN(FIELD, VALUE, LEN) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
memzero(msg_send.FIELD, sizeof(msg_send.FIELD)); \
|
||||
strncpy(msg_send.FIELD, VALUE, MIN(LEN, sizeof(msg_send.FIELD) - 1)); \
|
||||
}
|
||||
#define MSG_SEND_ASSIGN_BYTES(FIELD, VALUE, LEN) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
memzero(msg_send.FIELD.bytes, sizeof(msg_send.FIELD.bytes)); \
|
||||
memcpy(msg_send.FIELD.bytes, VALUE, \
|
||||
MIN(LEN, sizeof(msg_send.FIELD.bytes))); \
|
||||
msg_send.FIELD.size = MIN(LEN, sizeof(msg_send.FIELD.bytes)); \
|
||||
}
|
||||
#define MSG_SEND(TYPE) \
|
||||
_send_msg(iface_num, MessageType_MessageType_##TYPE, TYPE##_fields, &msg_send)
|
||||
static bool _read_authkey(pb_istream_t *stream, const pb_field_t *field,
|
||||
void **arg) {
|
||||
uint8_t *key_buffer = (uint8_t *)(*arg);
|
||||
|
||||
typedef struct {
|
||||
uint8_t iface_num;
|
||||
uint8_t packet_index;
|
||||
uint8_t packet_pos;
|
||||
uint8_t *buf;
|
||||
} usb_read_state;
|
||||
if (stream->bytes_left > BLE_GAP_PASSKEY_LEN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(key_buffer, 0, BLE_GAP_PASSKEY_LEN);
|
||||
|
||||
while (stream->bytes_left) {
|
||||
// read data
|
||||
if (!pb_read(stream, (pb_byte_t *)(key_buffer),
|
||||
(stream->bytes_left > BLE_GAP_PASSKEY_LEN)
|
||||
? BLE_GAP_PASSKEY_LEN
|
||||
: stream->bytes_left)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _usb_webusb_read_retry(uint8_t iface_num, uint8_t *buf) {
|
||||
for (int retry = 0;; retry++) {
|
||||
@ -221,16 +177,54 @@ static void _usb_webusb_read_retry(uint8_t iface_num, uint8_t *buf) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BLE
|
||||
static void _ble_read_retry(uint8_t iface_num, uint8_t *buf) {
|
||||
for (int retry = 0;; retry++) {
|
||||
int r = ble_ext_comm_receive(buf, BLE_PACKET_SIZE);
|
||||
if (r != BLE_PACKET_SIZE) { // reading failed
|
||||
if (r == 0 && retry < 500) {
|
||||
// only timeout => let's try again
|
||||
HAL_Delay(10);
|
||||
continue;
|
||||
} else {
|
||||
// error
|
||||
error_shutdown("BLE ERROR",
|
||||
"Error reading from BLE. Try different BLE cable.");
|
||||
}
|
||||
}
|
||||
return; // success
|
||||
}
|
||||
}
|
||||
|
||||
static void _ble_read_retry_int(uint8_t iface_num, uint8_t *buf) {
|
||||
for (int retry = 0;; retry++) {
|
||||
int r = ble_int_comm_receive(buf, USB_PACKET_SIZE);
|
||||
if (r == 0) { // reading failed
|
||||
if (retry < 500) {
|
||||
// only timeout => let's try again
|
||||
HAL_Delay(10);
|
||||
continue;
|
||||
} else {
|
||||
// error
|
||||
error_shutdown("BLE ERROR",
|
||||
"Error reading from BLE. Try different BLE cable.");
|
||||
}
|
||||
}
|
||||
return; // success
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* we don't use secbool/sectrue/secfalse here as it is a nanopb api */
|
||||
static bool _usb_read(pb_istream_t *stream, uint8_t *buf, size_t count) {
|
||||
usb_read_state *state = (usb_read_state *)(stream->state);
|
||||
static bool _read(pb_istream_t *stream, uint8_t *buf, size_t count) {
|
||||
read_state *state = (read_state *)(stream->state);
|
||||
|
||||
size_t read = 0;
|
||||
// while we have data left
|
||||
while (read < count) {
|
||||
size_t remaining = count - read;
|
||||
// if all remaining data fit into our packet
|
||||
if (state->packet_pos + remaining <= USB_PACKET_SIZE) {
|
||||
if (state->packet_pos + remaining <= state->packet_size) {
|
||||
// append data from buf to state->buf
|
||||
memcpy(buf + read, state->buf + state->packet_pos, remaining);
|
||||
// advance position
|
||||
@ -240,10 +234,19 @@ static bool _usb_read(pb_istream_t *stream, uint8_t *buf, size_t count) {
|
||||
} else {
|
||||
// append data that fits
|
||||
memcpy(buf + read, state->buf + state->packet_pos,
|
||||
USB_PACKET_SIZE - state->packet_pos);
|
||||
read += USB_PACKET_SIZE - state->packet_pos;
|
||||
state->packet_size - state->packet_pos);
|
||||
read += state->packet_size - state->packet_pos;
|
||||
// read next packet (with retry)
|
||||
_usb_webusb_read_retry(state->iface_num, state->buf);
|
||||
#ifdef USE_BLE
|
||||
if (state->iface_num == BLE_EXT_IFACE_NUM) {
|
||||
_ble_read_retry(state->iface_num, state->buf);
|
||||
} else if (state->iface_num == BLE_INT_IFACE_NUM) {
|
||||
_ble_read_retry_int(state->iface_num, state->buf);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
_usb_webusb_read_retry(state->iface_num, state->buf);
|
||||
}
|
||||
// prepare next packet
|
||||
state->packet_index++;
|
||||
state->packet_pos = MSG_HEADER2_LEN;
|
||||
@ -253,43 +256,24 @@ static bool _usb_read(pb_istream_t *stream, uint8_t *buf, size_t count) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _usb_read_flush(usb_read_state *state) { (void)state; }
|
||||
static void _read_flush(read_state *state) { (void)state; }
|
||||
|
||||
static secbool _recv_msg(uint8_t iface_num, uint32_t msg_size, uint8_t *buf,
|
||||
const pb_msgdesc_t *fields, void *msg) {
|
||||
usb_read_state state = {.iface_num = iface_num,
|
||||
.packet_index = 0,
|
||||
.packet_pos = MSG_HEADER1_LEN,
|
||||
.buf = buf};
|
||||
|
||||
pb_istream_t stream = {.callback = &_usb_read,
|
||||
.state = &state,
|
||||
.bytes_left = msg_size,
|
||||
.errmsg = NULL};
|
||||
|
||||
if (false == pb_decode_noinit(&stream, fields, msg)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
_usb_read_flush(&state);
|
||||
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
#define MSG_RECV_INIT(TYPE) TYPE msg_recv = TYPE##_init_default
|
||||
#define MSG_RECV_CALLBACK(FIELD, CALLBACK, ARGUMENT) \
|
||||
{ \
|
||||
msg_recv.FIELD.funcs.decode = &CALLBACK; \
|
||||
msg_recv.FIELD.arg = (void *)ARGUMENT; \
|
||||
}
|
||||
#define MSG_RECV(TYPE) \
|
||||
_recv_msg(iface_num, msg_size, buf, TYPE##_fields, &msg_recv)
|
||||
#define MSG_SEND_BLD(msg) (MSG_SEND(msg, _write, _write_flush))
|
||||
#ifdef USE_BLE
|
||||
#define MSG_RECV_BLD(msg, iface_num) \
|
||||
(MSG_RECV( \
|
||||
msg, _read, _read_flush, \
|
||||
((iface_num) == BLE_EXT_IFACE_NUM ? BLE_PACKET_SIZE : USB_PACKET_SIZE)))
|
||||
#else
|
||||
#define MSG_RECV_BLD(msg, iface_num) \
|
||||
(MSG_RECV(msg, _read, _read_flush, USB_PACKET_SIZE))
|
||||
#endif
|
||||
|
||||
void send_user_abort(uint8_t iface_num, const char *msg) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ActionCancelled);
|
||||
MSG_SEND_ASSIGN_STRING(message, msg);
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
}
|
||||
|
||||
static void send_msg_features(uint8_t iface_num,
|
||||
@ -316,19 +300,70 @@ static void send_msg_features(uint8_t iface_num,
|
||||
MSG_SEND_ASSIGN_VALUE(unit_color, unit_variant_get_color());
|
||||
MSG_SEND_ASSIGN_VALUE(unit_btconly, unit_variant_get_btconly());
|
||||
}
|
||||
|
||||
#if USE_OPTIGA
|
||||
MSG_SEND_ASSIGN_VALUE(bootloader_locked,
|
||||
(secret_bootloader_locked() == sectrue));
|
||||
#endif
|
||||
MSG_SEND(Features);
|
||||
MSG_SEND_BLD(Features);
|
||||
}
|
||||
|
||||
uint32_t process_msg_ComparisonRequest(uint8_t iface_num, uint32_t msg_size,
|
||||
uint8_t *buf) {
|
||||
uint8_t buffer[BLE_GAP_PASSKEY_LEN];
|
||||
MSG_RECV_INIT(ComparisonRequest);
|
||||
MSG_RECV_CALLBACK(key, _read_authkey, buffer);
|
||||
MSG_RECV_BLD(ComparisonRequest, iface_num);
|
||||
|
||||
uint32_t result = screen_comparison_confirm(buffer, BLE_GAP_PASSKEY_LEN);
|
||||
|
||||
if (result == INPUT_CONFIRM) {
|
||||
MSG_SEND_INIT(Success);
|
||||
MSG_SEND_BLD(Success);
|
||||
} else {
|
||||
send_user_abort(iface_num, "Pairing cancelled");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t process_msg_Pairing(uint8_t iface_num, uint32_t msg_size,
|
||||
uint8_t *buf) {
|
||||
uint8_t buffer[BLE_GAP_PASSKEY_LEN];
|
||||
MSG_RECV_INIT(PairingRequest);
|
||||
MSG_RECV_BLD(PairingRequest, iface_num);
|
||||
|
||||
uint32_t result = screen_pairing_confirm(buffer);
|
||||
|
||||
if (result == INPUT_CONFIRM) {
|
||||
MSG_SEND_INIT(AuthKey);
|
||||
MSG_SEND_CALLBACK(key, _write_authkey, buffer);
|
||||
MSG_SEND_BLD(AuthKey);
|
||||
} else {
|
||||
send_user_abort(iface_num, "Pairing cancelled");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t process_msg_Repair(uint8_t iface_num, uint32_t msg_size,
|
||||
uint8_t *buf) {
|
||||
MSG_RECV_INIT(RepairRequest);
|
||||
MSG_RECV_BLD(RepairRequest, iface_num);
|
||||
uint32_t result = screen_repair_confirm();
|
||||
if (result == INPUT_CONFIRM) {
|
||||
MSG_SEND_INIT(Success);
|
||||
MSG_SEND_BLD(Success);
|
||||
} else {
|
||||
send_user_abort(iface_num, "Pairing cancelled");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void process_msg_Initialize(uint8_t iface_num, uint32_t msg_size, uint8_t *buf,
|
||||
const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
MSG_RECV_INIT(Initialize);
|
||||
MSG_RECV(Initialize);
|
||||
MSG_RECV_BLD(Initialize, iface_num);
|
||||
send_msg_features(iface_num, vhdr, hdr);
|
||||
}
|
||||
|
||||
@ -336,17 +371,17 @@ void process_msg_GetFeatures(uint8_t iface_num, uint32_t msg_size, uint8_t *buf,
|
||||
const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
MSG_RECV_INIT(GetFeatures);
|
||||
MSG_RECV(GetFeatures);
|
||||
MSG_RECV_BLD(GetFeatures, iface_num);
|
||||
send_msg_features(iface_num, vhdr, hdr);
|
||||
}
|
||||
|
||||
void process_msg_Ping(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) {
|
||||
MSG_RECV_INIT(Ping);
|
||||
MSG_RECV(Ping);
|
||||
MSG_RECV_BLD(Ping, iface_num);
|
||||
|
||||
MSG_SEND_INIT(Success);
|
||||
MSG_SEND_ASSIGN_STRING(message, msg_recv.message);
|
||||
MSG_SEND(Success);
|
||||
MSG_SEND_BLD(Success);
|
||||
}
|
||||
|
||||
static uint32_t firmware_remaining;
|
||||
@ -362,7 +397,7 @@ void process_msg_FirmwareErase(uint8_t iface_num, uint32_t msg_size,
|
||||
erase_offset = 0;
|
||||
|
||||
MSG_RECV_INIT(FirmwareErase);
|
||||
MSG_RECV(FirmwareErase);
|
||||
MSG_RECV_BLD(FirmwareErase, iface_num);
|
||||
|
||||
firmware_remaining = msg_recv.has_length ? msg_recv.length : 0;
|
||||
if ((firmware_remaining > 0) &&
|
||||
@ -375,13 +410,13 @@ void process_msg_FirmwareErase(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(FirmwareRequest);
|
||||
MSG_SEND_ASSIGN_REQUIRED_VALUE(offset, 0);
|
||||
MSG_SEND_ASSIGN_REQUIRED_VALUE(length, chunk_requested);
|
||||
MSG_SEND(FirmwareRequest);
|
||||
MSG_SEND_BLD(FirmwareRequest);
|
||||
} else {
|
||||
// invalid firmware size
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Wrong firmware size");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
}
|
||||
}
|
||||
|
||||
@ -501,13 +536,13 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
uint8_t *buf) {
|
||||
MSG_RECV_INIT(FirmwareUpload);
|
||||
MSG_RECV_CALLBACK(payload, _read_payload, read_offset);
|
||||
const secbool r = MSG_RECV(FirmwareUpload);
|
||||
const secbool r = MSG_RECV_BLD(FirmwareUpload, iface_num);
|
||||
|
||||
if (sectrue != r || chunk_size != (chunk_requested + read_offset)) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid chunk size");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_INVALID_CHUNK_SIZE;
|
||||
}
|
||||
|
||||
@ -522,7 +557,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid vendor header");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_INVALID_VENDOR_HEADER;
|
||||
}
|
||||
|
||||
@ -530,7 +565,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid vendor header signature");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_INVALID_VENDOR_HEADER_SIG;
|
||||
}
|
||||
|
||||
@ -543,7 +578,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid firmware header");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_INVALID_IMAGE_HEADER;
|
||||
}
|
||||
|
||||
@ -551,7 +586,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Wrong firmware model");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_INVALID_IMAGE_MODEL;
|
||||
}
|
||||
|
||||
@ -560,7 +595,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid firmware signature");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_INVALID_IMAGE_HEADER_SIG;
|
||||
}
|
||||
|
||||
@ -611,7 +646,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Firmware mismatch");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_FIRMWARE_MISMATCH;
|
||||
}
|
||||
|
||||
@ -621,7 +656,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Not a firmware upgrade");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_NOT_FIRMWARE_UPGRADE;
|
||||
}
|
||||
|
||||
@ -629,7 +664,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Not a full-trust image");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_NOT_FULLTRUST_IMAGE;
|
||||
}
|
||||
|
||||
@ -681,7 +716,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
chunk_requested = chunk_limit - read_offset;
|
||||
MSG_SEND_ASSIGN_REQUIRED_VALUE(offset, read_offset);
|
||||
MSG_SEND_ASSIGN_REQUIRED_VALUE(length, chunk_requested);
|
||||
MSG_SEND(FirmwareRequest);
|
||||
MSG_SEND_BLD(FirmwareRequest);
|
||||
|
||||
firmware_remaining -= read_offset;
|
||||
return (int)firmware_remaining;
|
||||
@ -697,7 +732,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Firmware too big");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_FIRMWARE_TOO_BIG;
|
||||
}
|
||||
|
||||
@ -709,14 +744,14 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(FirmwareRequest);
|
||||
MSG_SEND_ASSIGN_REQUIRED_VALUE(offset, firmware_block * IMAGE_CHUNK_SIZE);
|
||||
MSG_SEND_ASSIGN_REQUIRED_VALUE(length, chunk_requested);
|
||||
MSG_SEND(FirmwareRequest);
|
||||
MSG_SEND_BLD(FirmwareRequest);
|
||||
return (int)firmware_remaining;
|
||||
}
|
||||
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid chunk hash");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return UPLOAD_ERR_INVALID_CHUNK_HASH;
|
||||
}
|
||||
|
||||
@ -784,15 +819,27 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_INIT(FirmwareRequest);
|
||||
MSG_SEND_ASSIGN_REQUIRED_VALUE(offset, firmware_block * IMAGE_CHUNK_SIZE);
|
||||
MSG_SEND_ASSIGN_REQUIRED_VALUE(length, chunk_requested);
|
||||
MSG_SEND(FirmwareRequest);
|
||||
MSG_SEND_BLD(FirmwareRequest);
|
||||
} else {
|
||||
MSG_SEND_INIT(Success);
|
||||
MSG_SEND(Success);
|
||||
MSG_SEND_BLD(Success);
|
||||
}
|
||||
return (int)firmware_remaining;
|
||||
}
|
||||
|
||||
secbool bootloader_WipeDevice(void) {
|
||||
#ifdef USE_BLE
|
||||
if (!ble_firmware_running()) {
|
||||
return secfalse;
|
||||
}
|
||||
stop_advertising();
|
||||
send_erase_bonds();
|
||||
|
||||
if (!wait_for_answer()) {
|
||||
return secfalse;
|
||||
}
|
||||
#endif
|
||||
|
||||
return flash_area_erase(&WIPE_AREA, ui_screen_wipe_progress);
|
||||
}
|
||||
|
||||
@ -802,11 +849,11 @@ int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Could not erase flash");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
return WIPE_ERR_CANNOT_ERASE;
|
||||
} else {
|
||||
MSG_SEND_INIT(Success);
|
||||
MSG_SEND(Success);
|
||||
MSG_SEND_BLD(Success);
|
||||
return WIPE_OK;
|
||||
}
|
||||
}
|
||||
@ -831,7 +878,7 @@ void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_UnexpectedMessage);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Unexpected message");
|
||||
MSG_SEND(Failure);
|
||||
MSG_SEND_BLD(Failure);
|
||||
}
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
|
@ -25,8 +25,10 @@
|
||||
#include "secbool.h"
|
||||
#include TREZOR_BOARD
|
||||
|
||||
#define USB_IFACE_NUM 0
|
||||
#define BLE_INT_IFACE_NUM 16
|
||||
#define BLE_EXT_IFACE_NUM 17
|
||||
#define USB_TIMEOUT 500
|
||||
#define USB_PACKET_SIZE 64
|
||||
|
||||
#define FIRMWARE_UPLOAD_CHUNK_RETRY_COUNT 2
|
||||
|
||||
@ -78,4 +80,11 @@ void process_msg_UnlockBootloader(uint8_t iface_num, uint32_t msg_size,
|
||||
|
||||
secbool bootloader_WipeDevice(void);
|
||||
|
||||
uint32_t process_msg_ComparisonRequest(uint8_t iface_num, uint32_t msg_size,
|
||||
uint8_t *buf);
|
||||
uint32_t process_msg_Pairing(uint8_t iface_num, uint32_t msg_size,
|
||||
uint8_t *buf);
|
||||
|
||||
uint32_t process_msg_Repair(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);
|
||||
|
||||
#endif
|
||||
|
@ -42,6 +42,18 @@ PB_BIND(FirmwareUpload, FirmwareUpload, AUTO)
|
||||
PB_BIND(UnlockBootloader, UnlockBootloader, AUTO)
|
||||
|
||||
|
||||
PB_BIND(PairingRequest, PairingRequest, AUTO)
|
||||
|
||||
|
||||
PB_BIND(AuthKey, AuthKey, AUTO)
|
||||
|
||||
|
||||
PB_BIND(RepairRequest, RepairRequest, AUTO)
|
||||
|
||||
|
||||
PB_BIND(ComparisonRequest, ComparisonRequest, AUTO)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -23,7 +23,11 @@ typedef enum _MessageType {
|
||||
MessageType_MessageType_ButtonRequest = 26,
|
||||
MessageType_MessageType_ButtonAck = 27,
|
||||
MessageType_MessageType_GetFeatures = 55,
|
||||
MessageType_MessageType_UnlockBootloader = 96
|
||||
MessageType_MessageType_UnlockBootloader = 96,
|
||||
MessageType_MessageType_PairingRequest = 8003,
|
||||
MessageType_MessageType_AuthKey = 8004,
|
||||
MessageType_MessageType_RepairRequest = 8005,
|
||||
MessageType_MessageType_ComparisonRequest = 8008
|
||||
} MessageType;
|
||||
|
||||
typedef enum _FailureType {
|
||||
@ -38,10 +42,18 @@ typedef enum _ButtonRequestType {
|
||||
} ButtonRequestType;
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _AuthKey {
|
||||
pb_callback_t key;
|
||||
} AuthKey;
|
||||
|
||||
typedef struct _ButtonAck {
|
||||
char dummy_field;
|
||||
} ButtonAck;
|
||||
|
||||
typedef struct _ComparisonRequest {
|
||||
pb_callback_t key;
|
||||
} ComparisonRequest;
|
||||
|
||||
typedef struct _GetFeatures {
|
||||
char dummy_field;
|
||||
} GetFeatures;
|
||||
@ -50,6 +62,14 @@ typedef struct _Initialize {
|
||||
char dummy_field;
|
||||
} Initialize;
|
||||
|
||||
typedef struct _PairingRequest {
|
||||
char dummy_field;
|
||||
} PairingRequest;
|
||||
|
||||
typedef struct _RepairRequest {
|
||||
char dummy_field;
|
||||
} RepairRequest;
|
||||
|
||||
typedef struct _UnlockBootloader {
|
||||
char dummy_field;
|
||||
} UnlockBootloader;
|
||||
@ -137,8 +157,8 @@ typedef struct _Success {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _MessageType_MIN MessageType_MessageType_Initialize
|
||||
#define _MessageType_MAX MessageType_MessageType_UnlockBootloader
|
||||
#define _MessageType_ARRAYSIZE ((MessageType)(MessageType_MessageType_UnlockBootloader+1))
|
||||
#define _MessageType_MAX MessageType_MessageType_ComparisonRequest
|
||||
#define _MessageType_ARRAYSIZE ((MessageType)(MessageType_MessageType_ComparisonRequest+1))
|
||||
|
||||
#define _FailureType_MIN FailureType_Failure_UnexpectedMessage
|
||||
#define _FailureType_MAX FailureType_Failure_ProcessError
|
||||
@ -166,6 +186,10 @@ extern "C" {
|
||||
#define FirmwareRequest_init_default {0, 0}
|
||||
#define FirmwareUpload_init_default {{{NULL}, NULL}, false, {0, {0}}}
|
||||
#define UnlockBootloader_init_default {0}
|
||||
#define PairingRequest_init_default {0}
|
||||
#define AuthKey_init_default {{{NULL}, NULL}}
|
||||
#define RepairRequest_init_default {0}
|
||||
#define ComparisonRequest_init_default {{{NULL}, NULL}}
|
||||
#define Initialize_init_zero {0}
|
||||
#define GetFeatures_init_zero {0}
|
||||
#define Features_init_zero {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0}
|
||||
@ -178,8 +202,14 @@ extern "C" {
|
||||
#define FirmwareRequest_init_zero {0, 0}
|
||||
#define FirmwareUpload_init_zero {{{NULL}, NULL}, false, {0, {0}}}
|
||||
#define UnlockBootloader_init_zero {0}
|
||||
#define PairingRequest_init_zero {0}
|
||||
#define AuthKey_init_zero {{{NULL}, NULL}}
|
||||
#define RepairRequest_init_zero {0}
|
||||
#define ComparisonRequest_init_zero {{{NULL}, NULL}}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define AuthKey_key_tag 1
|
||||
#define ComparisonRequest_key_tag 1
|
||||
#define ButtonRequest_code_tag 1
|
||||
#define Failure_code_tag 1
|
||||
#define Failure_message_tag 2
|
||||
@ -294,6 +324,26 @@ X(a, STATIC, OPTIONAL, BYTES, hash, 2)
|
||||
#define UnlockBootloader_CALLBACK NULL
|
||||
#define UnlockBootloader_DEFAULT NULL
|
||||
|
||||
#define PairingRequest_FIELDLIST(X, a) \
|
||||
|
||||
#define PairingRequest_CALLBACK NULL
|
||||
#define PairingRequest_DEFAULT NULL
|
||||
|
||||
#define AuthKey_FIELDLIST(X, a) \
|
||||
X(a, CALLBACK, REQUIRED, BYTES, key, 1)
|
||||
#define AuthKey_CALLBACK pb_default_field_callback
|
||||
#define AuthKey_DEFAULT NULL
|
||||
|
||||
#define RepairRequest_FIELDLIST(X, a) \
|
||||
|
||||
#define RepairRequest_CALLBACK NULL
|
||||
#define RepairRequest_DEFAULT NULL
|
||||
|
||||
#define ComparisonRequest_FIELDLIST(X, a) \
|
||||
X(a, CALLBACK, REQUIRED, BYTES, key, 1)
|
||||
#define ComparisonRequest_CALLBACK pb_default_field_callback
|
||||
#define ComparisonRequest_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t Initialize_msg;
|
||||
extern const pb_msgdesc_t GetFeatures_msg;
|
||||
extern const pb_msgdesc_t Features_msg;
|
||||
@ -306,6 +356,10 @@ extern const pb_msgdesc_t FirmwareErase_msg;
|
||||
extern const pb_msgdesc_t FirmwareRequest_msg;
|
||||
extern const pb_msgdesc_t FirmwareUpload_msg;
|
||||
extern const pb_msgdesc_t UnlockBootloader_msg;
|
||||
extern const pb_msgdesc_t PairingRequest_msg;
|
||||
extern const pb_msgdesc_t AuthKey_msg;
|
||||
extern const pb_msgdesc_t RepairRequest_msg;
|
||||
extern const pb_msgdesc_t ComparisonRequest_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define Initialize_fields &Initialize_msg
|
||||
@ -320,9 +374,15 @@ extern const pb_msgdesc_t UnlockBootloader_msg;
|
||||
#define FirmwareRequest_fields &FirmwareRequest_msg
|
||||
#define FirmwareUpload_fields &FirmwareUpload_msg
|
||||
#define UnlockBootloader_fields &UnlockBootloader_msg
|
||||
#define PairingRequest_fields &PairingRequest_msg
|
||||
#define AuthKey_fields &AuthKey_msg
|
||||
#define RepairRequest_fields &RepairRequest_msg
|
||||
#define ComparisonRequest_fields &ComparisonRequest_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* FirmwareUpload_size depends on runtime parameters */
|
||||
/* AuthKey_size depends on runtime parameters */
|
||||
/* ComparisonRequest_size depends on runtime parameters */
|
||||
#define ButtonAck_size 0
|
||||
#define ButtonRequest_size 2
|
||||
#define Failure_size 260
|
||||
@ -331,7 +391,9 @@ extern const pb_msgdesc_t UnlockBootloader_msg;
|
||||
#define FirmwareRequest_size 12
|
||||
#define GetFeatures_size 0
|
||||
#define Initialize_size 0
|
||||
#define PairingRequest_size 0
|
||||
#define Ping_size 258
|
||||
#define RepairRequest_size 0
|
||||
#define Success_size 258
|
||||
#define UnlockBootloader_size 0
|
||||
|
||||
|
@ -18,6 +18,10 @@ enum MessageType {
|
||||
MessageType_ButtonAck = 27;
|
||||
MessageType_GetFeatures = 55;
|
||||
MessageType_UnlockBootloader = 96;
|
||||
MessageType_PairingRequest = 8003;
|
||||
MessageType_AuthKey = 8004;
|
||||
MessageType_RepairRequest = 8005;
|
||||
MessageType_ComparisonRequest = 8008;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,3 +159,43 @@ message FirmwareUpload {
|
||||
*/
|
||||
message UnlockBootloader {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Request: initiates new pairing request
|
||||
* @start
|
||||
* @next AuthKey
|
||||
* @next Failure
|
||||
*/
|
||||
message PairingRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Request: confirms pairing request with auth key entered on the device
|
||||
* @end
|
||||
*/
|
||||
message AuthKey {
|
||||
required bytes key = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Request: initiates repairing request
|
||||
* @start
|
||||
* @next Success
|
||||
* @next Failure
|
||||
*/
|
||||
message RepairRequest {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Request: initiates new pairing request with numeric comparison
|
||||
* @start
|
||||
* @next Success
|
||||
* @next Failure
|
||||
*/
|
||||
message ComparisonRequest {
|
||||
required bytes key = 1;
|
||||
}
|
||||
|
@ -155,7 +155,6 @@ STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref,
|
||||
return mp_const_true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_BLE
|
||||
else if (iface == BLE_EVENTS_IFACE) {
|
||||
ble_event_poll();
|
||||
|
87
core/embed/lib/protob_helpers.c
Normal file
87
core/embed/lib/protob_helpers.c
Normal file
@ -0,0 +1,87 @@
|
||||
|
||||
|
||||
#include "protob_helpers.h"
|
||||
|
||||
secbool send_protob_msg(uint8_t iface_num, uint16_t msg_id,
|
||||
const pb_msgdesc_t *fields, const void *msg,
|
||||
bool (*write)(pb_ostream_t *stream,
|
||||
const pb_byte_t *buf, size_t count),
|
||||
void (*write_flush)(write_state *state)) {
|
||||
// determine message size by serializing it into a dummy stream
|
||||
pb_ostream_t sizestream = {.callback = NULL,
|
||||
.state = NULL,
|
||||
.max_size = SIZE_MAX,
|
||||
.bytes_written = 0,
|
||||
.errmsg = NULL};
|
||||
if (false == pb_encode(&sizestream, fields, msg)) {
|
||||
return secfalse;
|
||||
}
|
||||
const uint32_t msg_size = sizestream.bytes_written;
|
||||
|
||||
write_state state = {
|
||||
.iface_num = iface_num,
|
||||
.packet_index = 0,
|
||||
.packet_pos = MSG_HEADER1_LEN,
|
||||
.buf =
|
||||
{
|
||||
'?',
|
||||
'#',
|
||||
'#',
|
||||
(msg_id >> 8) & 0xFF,
|
||||
msg_id & 0xFF,
|
||||
(msg_size >> 24) & 0xFF,
|
||||
(msg_size >> 16) & 0xFF,
|
||||
(msg_size >> 8) & 0xFF,
|
||||
msg_size & 0xFF,
|
||||
},
|
||||
};
|
||||
|
||||
pb_ostream_t stream = {.callback = write,
|
||||
.state = &state,
|
||||
.max_size = SIZE_MAX,
|
||||
.bytes_written = 0,
|
||||
.errmsg = NULL};
|
||||
|
||||
if (false == pb_encode(&stream, fields, msg)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
write_flush(&state);
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
secbool recv_protob_msg(uint8_t iface_num, uint32_t msg_size, uint8_t *buf,
|
||||
const pb_msgdesc_t *fields, void *msg,
|
||||
bool (*read)(pb_istream_t *stream, pb_byte_t *buf,
|
||||
size_t count),
|
||||
void (*read_flush)(read_state *state),
|
||||
uint16_t packet_size) {
|
||||
read_state state = {.iface_num = iface_num,
|
||||
.packet_index = 0,
|
||||
.packet_pos = MSG_HEADER1_LEN,
|
||||
.packet_size = packet_size,
|
||||
.buf = buf};
|
||||
|
||||
pb_istream_t stream = {.callback = read,
|
||||
.state = &state,
|
||||
.bytes_left = msg_size,
|
||||
.errmsg = NULL};
|
||||
|
||||
if (false == pb_decode_noinit(&stream, fields, msg)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
read_flush(&state);
|
||||
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id,
|
||||
uint32_t *msg_size) {
|
||||
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') {
|
||||
return secfalse;
|
||||
}
|
||||
*msg_id = (buf[3] << 8) + buf[4];
|
||||
*msg_size = (buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8];
|
||||
return sectrue;
|
||||
}
|
87
core/embed/lib/protob_helpers.h
Normal file
87
core/embed/lib/protob_helpers.h
Normal file
@ -0,0 +1,87 @@
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "secbool.h"
|
||||
|
||||
#define USB_PACKET_SIZE 64
|
||||
#define MSG_HEADER1_LEN 9
|
||||
#define MSG_HEADER2_LEN 1
|
||||
|
||||
#define MSG_SEND_INIT(TYPE) TYPE msg_send = TYPE##_init_default
|
||||
#define MSG_SEND_ASSIGN_REQUIRED_VALUE(FIELD, VALUE) \
|
||||
{ msg_send.FIELD = VALUE; }
|
||||
#define MSG_SEND_ASSIGN_VALUE(FIELD, VALUE) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
msg_send.FIELD = VALUE; \
|
||||
}
|
||||
#define MSG_SEND_ASSIGN_STRING(FIELD, VALUE) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
memzero(msg_send.FIELD, sizeof(msg_send.FIELD)); \
|
||||
strncpy(msg_send.FIELD, VALUE, sizeof(msg_send.FIELD) - 1); \
|
||||
}
|
||||
#define MSG_SEND_ASSIGN_STRING_LEN(FIELD, VALUE, LEN) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
memzero(msg_send.FIELD, sizeof(msg_send.FIELD)); \
|
||||
strncpy(msg_send.FIELD, VALUE, MIN(LEN, sizeof(msg_send.FIELD) - 1)); \
|
||||
}
|
||||
#define MSG_SEND_ASSIGN_BYTES(FIELD, VALUE, LEN) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
memzero(msg_send.FIELD.bytes, sizeof(msg_send.FIELD.bytes)); \
|
||||
memcpy(msg_send.FIELD.bytes, VALUE, \
|
||||
MIN(LEN, sizeof(msg_send.FIELD.bytes))); \
|
||||
msg_send.FIELD.size = MIN(LEN, sizeof(msg_send.FIELD.bytes)); \
|
||||
}
|
||||
#define MSG_SEND_CALLBACK(FIELD, CALLBACK, ARGUMENT) \
|
||||
{ \
|
||||
msg_send.FIELD.funcs.encode = &CALLBACK; \
|
||||
msg_send.FIELD.arg = (void *)ARGUMENT; \
|
||||
}
|
||||
#define MSG_SEND(TYPE, WRITE, WRITE_FLUSH) \
|
||||
send_protob_msg(iface_num, MessageType_MessageType_##TYPE, TYPE##_fields, \
|
||||
&msg_send, WRITE, WRITE_FLUSH)
|
||||
|
||||
#define MSG_RECV_INIT(TYPE) TYPE msg_recv = TYPE##_init_default
|
||||
#define MSG_RECV_CALLBACK(FIELD, CALLBACK, ARGUMENT) \
|
||||
{ \
|
||||
msg_recv.FIELD.funcs.decode = &CALLBACK; \
|
||||
msg_recv.FIELD.arg = (void *)ARGUMENT; \
|
||||
}
|
||||
#define MSG_RECV(TYPE, READ, READ_FLUSH, PACKET_SIZE) \
|
||||
recv_protob_msg(iface_num, msg_size, buf, TYPE##_fields, &msg_recv, READ, \
|
||||
READ_FLUSH, PACKET_SIZE)
|
||||
|
||||
typedef struct {
|
||||
uint8_t iface_num;
|
||||
uint8_t packet_index;
|
||||
uint8_t packet_pos;
|
||||
uint8_t buf[USB_PACKET_SIZE];
|
||||
} write_state;
|
||||
|
||||
typedef struct {
|
||||
uint8_t iface_num;
|
||||
uint8_t packet_index;
|
||||
uint8_t packet_pos;
|
||||
uint16_t packet_size;
|
||||
uint8_t *buf;
|
||||
} read_state;
|
||||
|
||||
secbool send_protob_msg(uint8_t iface_num, uint16_t msg_id,
|
||||
const pb_msgdesc_t *fields, const void *msg,
|
||||
bool (*write_fnc)(pb_ostream_t *stream,
|
||||
const pb_byte_t *buf, size_t count),
|
||||
void (*write_flush)(write_state *state));
|
||||
|
||||
secbool recv_protob_msg(uint8_t iface_num, uint32_t msg_size, uint8_t *buf,
|
||||
const pb_msgdesc_t *fields, void *msg,
|
||||
bool (*read)(pb_istream_t *stream, pb_byte_t *buf,
|
||||
size_t count),
|
||||
void (*read_flush)(read_state *state),
|
||||
uint16_t packet_size);
|
||||
|
||||
secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id,
|
||||
uint32_t *msg_size);
|
@ -369,6 +369,9 @@ fn generate_trezorhal_bindings() {
|
||||
.no_copy("buffer_jpeg_work_t")
|
||||
.no_copy("buffer_blurring_t")
|
||||
.no_copy("buffer_blurring_totals_t")
|
||||
// ble
|
||||
.allowlist_function("ble_connected")
|
||||
.allowlist_function("start_advertising")
|
||||
//usb
|
||||
.allowlist_function("usb_configured")
|
||||
// touch
|
||||
|
@ -15,7 +15,7 @@ uint32_t screen_intro(const char* bld_version_str, const char* vendor_str,
|
||||
uint8_t vendor_str_len, const char* version_str,
|
||||
bool fw_ok);
|
||||
uint32_t screen_menu(secbool firmware_present);
|
||||
void screen_connect(bool initial_setup);
|
||||
void screen_connect(bool initial_setup, uint8_t iface);
|
||||
void screen_fatal_error_rust(const char* title, const char* msg,
|
||||
const char* footer);
|
||||
void screen_wipe_success(void);
|
||||
@ -28,6 +28,11 @@ void screen_boot_empty(bool fading);
|
||||
void screen_boot_full(void);
|
||||
uint32_t screen_unlock_bootloader_confirm(void);
|
||||
void screen_unlock_bootloader_success(void);
|
||||
|
||||
uint32_t screen_pairing_confirm(uint8_t* buffer);
|
||||
uint32_t screen_comparison_confirm(uint8_t* code, uint8_t code_len);
|
||||
uint32_t screen_repair_confirm(void);
|
||||
|
||||
void display_image(int16_t x, int16_t y, const uint8_t* data, uint32_t datalen);
|
||||
void display_icon(int16_t x, int16_t y, const uint8_t* data, uint32_t datalen,
|
||||
uint16_t fg_color, uint16_t bg_color);
|
||||
|
9
core/embed/rust/src/trezorhal/ble.rs
Normal file
9
core/embed/rust/src/trezorhal/ble.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use super::ffi;
|
||||
|
||||
pub fn ble_connected() -> bool {
|
||||
unsafe { ffi::ble_connected() }
|
||||
}
|
||||
|
||||
pub fn start_advertising(whitelist: bool) {
|
||||
unsafe { ffi::start_advertising(whitelist) }
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
pub mod bip39;
|
||||
#[cfg(feature = "ble")]
|
||||
pub mod ble;
|
||||
#[macro_use]
|
||||
#[allow(unused_macros)]
|
||||
pub mod fatal_error;
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||
bootloader::{connect::Connect, welcome::Welcome},
|
||||
component::{
|
||||
bl_confirm::{Confirm, ConfirmTitle},
|
||||
Button, ResultScreen, WelcomeScreen,
|
||||
Button, PinKeyboard, ResultScreen, WelcomeScreen,
|
||||
},
|
||||
constant,
|
||||
theme::{
|
||||
@ -28,6 +28,7 @@ use crate::{
|
||||
util::{from_c_array, from_c_str},
|
||||
},
|
||||
};
|
||||
use core::slice;
|
||||
use heapless::String;
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
@ -36,7 +37,13 @@ pub mod intro;
|
||||
pub mod menu;
|
||||
pub mod welcome;
|
||||
|
||||
use crate::{trezorhal::secbool::secbool, ui::model_tt::theme::BLACK};
|
||||
use crate::{
|
||||
trezorhal::secbool::secbool,
|
||||
ui::{
|
||||
geometry::Alignment,
|
||||
model_tt::theme::{bootloader::text_title, BLACK},
|
||||
},
|
||||
};
|
||||
use intro::Intro;
|
||||
use menu::Menu;
|
||||
|
||||
@ -71,13 +78,16 @@ fn fadeout() {
|
||||
display::fade_backlight_duration(BACKLIGHT_DIM, 150);
|
||||
}
|
||||
|
||||
fn run<F>(frame: &mut F) -> u32
|
||||
fn run<F>(frame: &mut F, clear: bool) -> u32
|
||||
where
|
||||
F: Component,
|
||||
F::Msg: ReturnToC,
|
||||
{
|
||||
frame.place(constant::screen());
|
||||
fadeout();
|
||||
if clear {
|
||||
display::rect_fill(screen(), BLACK);
|
||||
}
|
||||
display::sync();
|
||||
frame.paint();
|
||||
display::refresh();
|
||||
@ -187,7 +197,7 @@ extern "C" fn screen_install_confirm(
|
||||
frame = frame.with_alert(alert);
|
||||
}
|
||||
|
||||
run(&mut frame)
|
||||
run(&mut frame, false)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -206,12 +216,12 @@ extern "C" fn screen_wipe_confirm() -> u32 {
|
||||
let mut frame =
|
||||
Confirm::new(BLD_WIPE_COLOR, left, right, ConfirmTitle::Icon(icon), msg).with_alert(alert);
|
||||
|
||||
run(&mut frame)
|
||||
run(&mut frame, false)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_menu(firmware_present: secbool) -> u32 {
|
||||
run(&mut Menu::new(firmware_present))
|
||||
run(&mut Menu::new(firmware_present), false)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -238,7 +248,7 @@ extern "C" fn screen_intro(
|
||||
|
||||
let mut frame = Intro::new(title_str.as_str(), version_str.as_str(), fw_ok);
|
||||
|
||||
run(&mut frame)
|
||||
run(&mut frame, false)
|
||||
}
|
||||
|
||||
fn screen_progress(
|
||||
@ -297,9 +307,14 @@ extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_connect(initial_setup: bool) {
|
||||
extern "C" fn screen_connect(initial_setup: bool, iface: u8) {
|
||||
let bg = if initial_setup { WELCOME_COLOR } else { BLD_BG };
|
||||
let mut frame = Connect::new("Waiting for host...", bg);
|
||||
|
||||
let mut frame = if iface == 0 {
|
||||
Connect::new("Waiting for host...(USB)", bg)
|
||||
} else {
|
||||
Connect::new("Waiting for host...(BLE)", bg)
|
||||
};
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
@ -421,3 +436,56 @@ extern "C" fn bld_continue_label(bg_color: cty::uint16_t) {
|
||||
Color::from_u16(bg_color),
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_pairing_confirm(buffer: *const cty::uint8_t) -> u32 {
|
||||
let pin_slice = unsafe { slice::from_raw_parts_mut(buffer as *mut u8, 6) };
|
||||
|
||||
let mut pin = PinKeyboard::new("Enter passkey", "", None, true);
|
||||
let res = run(&mut pin, true);
|
||||
|
||||
if res == 2 {
|
||||
let pin = pin.pin().as_bytes();
|
||||
if pin.len() == 6 {
|
||||
pin_slice.copy_from_slice(&pin[0..6]);
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_comparison_confirm(code: *const cty::uint8_t, code_len: u8) -> u32 {
|
||||
let code = unwrap!(unsafe { from_c_array(code, code_len as usize) });
|
||||
|
||||
let right = Button::with_text("YES").styled(button_confirm());
|
||||
let left = Button::with_text("CANCEL").styled(button_bld());
|
||||
let title = Label::new(
|
||||
"DO THE NUMBERS MATCH?",
|
||||
Alignment::Start,
|
||||
text_title(BLD_BG),
|
||||
)
|
||||
.vertically_centered();
|
||||
|
||||
let mut frame = Confirm::new(
|
||||
BLD_BG,
|
||||
left,
|
||||
right,
|
||||
ConfirmTitle::Text(title),
|
||||
Label::new(code, Alignment::Center, TEXT_NORMAL),
|
||||
);
|
||||
|
||||
run(&mut frame, true)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_repair_confirm() -> u32 {
|
||||
let msg = Label::new("Allow repair?", Alignment::Center, TEXT_NORMAL);
|
||||
let right = Button::with_text("ALLOW").styled(button_confirm());
|
||||
let left = Button::with_text("DENY").styled(button_bld());
|
||||
let title = Label::new("REPAIR", Alignment::Start, text_title(BLD_BG)).vertically_centered();
|
||||
|
||||
let mut frame = Confirm::new(BLD_BG, left, right, ConfirmTitle::Text(title), msg);
|
||||
|
||||
run(&mut frame, true)
|
||||
}
|
||||
|
@ -19,9 +19,10 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, ToPrimitive)]
|
||||
pub enum PinKeyboardMsg {
|
||||
Confirmed,
|
||||
Cancelled,
|
||||
Cancelled = 1,
|
||||
Confirmed = 2,
|
||||
}
|
||||
|
||||
const MAX_LENGTH: usize = 50;
|
||||
|
@ -231,6 +231,8 @@ pub fn button_bld() -> ButtonStyleSheet {
|
||||
}
|
||||
}
|
||||
|
||||
pub const TEXT_NORMAL_BLACK: TextStyle = TextStyle::new(Font::NORMAL, WHITE, BLACK, WHITE, WHITE);
|
||||
|
||||
pub const fn text_title(bg: Color) -> TextStyle {
|
||||
TextStyle::new(
|
||||
Font::BOLD,
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include TREZOR_BOARD
|
||||
#include "ble/state.h"
|
||||
#include "buffers.h"
|
||||
#include "button.h"
|
||||
#include "common.h"
|
||||
|
208
core/embed/segger/SEGGER_MMD/HardFaultHandler.S
Normal file
208
core/embed/segger/SEGGER_MMD/HardFaultHandler.S
Normal file
@ -0,0 +1,208 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2014 - 2020 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* - Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* - Neither the name of SEGGER Microcontroller GmbH *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. *
|
||||
* IN NO EVENT SHALL SEGGER Microcontroller GmbH BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
;
|
||||
;----------------------------------------------------------------------
|
||||
;File : HardFaultHandler.S
|
||||
;Purpose : HardFault exception handler for IAR, Keil and GNU assembler.
|
||||
; Evaluates used stack (MSP, PSP) and passes appropiate stack
|
||||
; pointer to the HardFaultHandler "C"-routine.
|
||||
;------------- END-OF-HEADER ------------------------------------------
|
||||
;*/
|
||||
|
||||
#ifndef __IAR_SYSTEMS_ASM__
|
||||
#ifndef __CC_ARM
|
||||
#ifndef __clang__
|
||||
#ifndef __GNUC__
|
||||
#error "Unsupported assembler!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* Forward declarations of segments used
|
||||
;*
|
||||
;**********************************************************************
|
||||
;*/
|
||||
|
||||
#if (defined(__IAR_SYSTEMS_ASM__))
|
||||
|
||||
SECTION CODE:CODE:NOROOT(2)
|
||||
SECTION CSTACK:DATA:NOROOT(3)
|
||||
|
||||
#elif (defined(__CC_ARM))
|
||||
|
||||
AREA OSKERNEL, CODE, READONLY, ALIGN=2
|
||||
PRESERVE8
|
||||
|
||||
#endif
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* Publics
|
||||
;*
|
||||
;**********************************************************************
|
||||
;*/
|
||||
|
||||
#if (defined(__IAR_SYSTEMS_ASM__))
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
PUBLIC HardFault_Handler
|
||||
|
||||
#elif (defined(__CC_ARM))
|
||||
|
||||
EXPORT HardFault_Handler
|
||||
|
||||
#elif (defined(__clang__) || defined(__GNUC__))
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, function
|
||||
|
||||
#endif
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* Externals, code
|
||||
;*
|
||||
;**********************************************************************
|
||||
;*/
|
||||
|
||||
#if (defined(__IAR_SYSTEMS_ASM__))
|
||||
|
||||
EXTERN HardFaultHandler
|
||||
|
||||
#elif (defined(__CC_ARM))
|
||||
|
||||
IMPORT HardFaultHandler
|
||||
|
||||
#elif (defined(__clang__) || defined(__GNUC__))
|
||||
|
||||
.extern HardFaultHandler
|
||||
|
||||
#endif
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* CODE segment
|
||||
;*
|
||||
;**********************************************************************
|
||||
;*/
|
||||
|
||||
#if (defined(__clang__) || defined(__GNUC__))
|
||||
|
||||
.syntax unified
|
||||
.thumb
|
||||
.balign 4
|
||||
.text
|
||||
|
||||
#else
|
||||
|
||||
THUMB
|
||||
|
||||
#endif
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* Global functions
|
||||
;*
|
||||
;**********************************************************************
|
||||
;*/
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* HardFault_Handler()
|
||||
;*
|
||||
;* Function description
|
||||
;* Evaluates the used stack (MSP, PSP) and passes the appropiate
|
||||
;* stack pointer to the HardFaultHandler "C"-routine.
|
||||
;*
|
||||
;* Notes
|
||||
;* (1) Ensure that HardFault_Handler is part of the exception table
|
||||
;*/
|
||||
#if (defined(__clang__) || defined(__GNUC__))
|
||||
HardFault_Handler:
|
||||
#else
|
||||
HardFault_Handler
|
||||
#endif
|
||||
#if (defined(__IAR_SYSTEMS_ASM__) && defined(__ARM6M__) && (__CORE__ == __ARM6M__)) || \
|
||||
(defined(__CC_ARM) && defined(__TARGET_ARCH_6S_M)) || \
|
||||
(defined(__clang__) && defined(__ARM_ARCH) && (__ARM_ARCH == 6)) || \
|
||||
(defined(__GNUC__) && (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__)))
|
||||
;// This version is for Cortex M0
|
||||
movs R0, #4
|
||||
mov R1, LR
|
||||
tst R0, R1 ;// Check EXC_RETURN in Link register bit 2.
|
||||
bne Uses_PSP
|
||||
mrs R0, MSP ;// Stacking was using MSP.
|
||||
b Pass_StackPtr
|
||||
#if (defined(__clang__) || defined(__GNUC__))
|
||||
Uses_PSP:
|
||||
#else
|
||||
Uses_PSP
|
||||
#endif
|
||||
mrs R0, PSP ;// Stacking was using PSP.
|
||||
#if (defined(__GNUC__) || defined(__clang__))
|
||||
Pass_StackPtr:
|
||||
#else
|
||||
Pass_StackPtr
|
||||
#endif
|
||||
#else
|
||||
;// This version is for Cortex M3, Cortex M4 and Cortex M4F
|
||||
tst LR, #4 ;// Check EXC_RETURN in Link register bit 2.
|
||||
ite EQ
|
||||
mrseq R0, MSP ;// Stacking was using MSP.
|
||||
mrsne R0, PSP ;// Stacking was using PSP.
|
||||
#endif
|
||||
#if (defined(__CC_ARM))
|
||||
ALIGN
|
||||
#endif
|
||||
ldr R1,=HardFaultHandler
|
||||
bx R1 ;// Stack pointer passed through R0.
|
||||
|
||||
#if (defined(__clang__) || defined(__GNUC__))
|
||||
.end
|
||||
#else
|
||||
END
|
||||
#endif
|
||||
|
||||
;/****** End Of File *************************************************/
|
155
core/embed/segger/SEGGER_MMD/JLINK_MONITOR.c
Normal file
155
core/embed/segger/SEGGER_MMD/JLINK_MONITOR.c
Normal file
@ -0,0 +1,155 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 1995 - 2018 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the monitor mode protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* - Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* - Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* - Neither the name of SEGGER Microcontroller GmbH *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
----------------------------------------------------------------------
|
||||
File : JLINK_MONITOR.c
|
||||
Purpose : Implementation of debug monitor for J-Link monitor mode debug on Cortex-M devices.
|
||||
-------- END-OF-HEADER ---------------------------------------------
|
||||
*/
|
||||
|
||||
#include "JLINK_MONITOR.h"
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Configuration
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Types
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Static data
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Local functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Global functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* JLINK_MONITOR_OnExit()
|
||||
*
|
||||
* Function description
|
||||
* Called from DebugMon_Handler(), once per debug exit.
|
||||
* May perform some target specific operations to be done on debug mode exit.
|
||||
*
|
||||
* Notes
|
||||
* (1) Must not keep the CPU busy for more than 100 ms
|
||||
*/
|
||||
void JLINK_MONITOR_OnExit(void) {
|
||||
//
|
||||
// Add custom code here
|
||||
//
|
||||
// BSP_ClrLED(0);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* JLINK_MONITOR_OnEnter()
|
||||
*
|
||||
* Function description
|
||||
* Called from DebugMon_Handler(), once per debug entry.
|
||||
* May perform some target specific operations to be done on debug mode entry
|
||||
*
|
||||
* Notes
|
||||
* (1) Must not keep the CPU busy for more than 100 ms
|
||||
*/
|
||||
void JLINK_MONITOR_OnEnter(void) {
|
||||
//
|
||||
// Add custom code here
|
||||
//
|
||||
// BSP_SetLED(0);
|
||||
// BSP_ClrLED(1);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* JLINK_MONITOR_OnPoll()
|
||||
*
|
||||
* Function description
|
||||
* Called periodically from DebugMon_Handler(), to perform some actions that need to be performed periodically during debug mode.
|
||||
*
|
||||
* Notes
|
||||
* (1) Must not keep the CPU busy for more than 100 ms
|
||||
*/
|
||||
void JLINK_MONITOR_OnPoll(void) {
|
||||
//
|
||||
// Add custom code here
|
||||
//
|
||||
// BSP_ToggleLED(0);
|
||||
// _Delay(500000);
|
||||
}
|
||||
|
||||
/****** End Of File *************************************************/
|
65
core/embed/segger/SEGGER_MMD/JLINK_MONITOR.h
Normal file
65
core/embed/segger/SEGGER_MMD/JLINK_MONITOR.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 1995 - 2018 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the monitor mode protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* - Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* - Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* - Neither the name of SEGGER Microcontroller GmbH *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
----------------------------------------------------------------------
|
||||
File : JLINK_MONITOR.h
|
||||
Purpose : Header file of debug monitor for J-Link monitor mode debug on Cortex-M devices.
|
||||
-------- END-OF-HEADER ---------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef JLINK_MONITOR_H
|
||||
#define JLINK_MONITOR_H
|
||||
|
||||
void JLINK_MONITOR_OnExit (void);
|
||||
void JLINK_MONITOR_OnEnter (void);
|
||||
void JLINK_MONITOR_OnPoll (void);
|
||||
|
||||
#endif
|
||||
|
||||
/****** End Of File *************************************************/
|
927
core/embed/segger/SEGGER_MMD/JLINK_MONITOR_ISR_SES.S
Normal file
927
core/embed/segger/SEGGER_MMD/JLINK_MONITOR_ISR_SES.S
Normal file
@ -0,0 +1,927 @@
|
||||
/*********************************************************************
|
||||
* (c) SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
* www.segger.com *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 1995 - 2020 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the monitor mode protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* - Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* - Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* - Neither the name of SEGGER Microcontroller GmbH *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
----------------------------------------------------------------------
|
||||
File : JLINK_MONITOR_ISR_SES.s
|
||||
Purpose : Implementation of debug monitor for J-Link monitor mode
|
||||
debug on Cortex-M devices, supporting SES compiler.
|
||||
-------- END-OF-HEADER ---------------------------------------------
|
||||
*/
|
||||
|
||||
.name JLINK_MONITOR_ISR
|
||||
.syntax unified
|
||||
|
||||
.extern JLINK_MONITOR_OnEnter
|
||||
.extern JLINK_MONITOR_OnExit
|
||||
.extern JLINK_MONITOR_OnPoll
|
||||
|
||||
.global DebugMon_Handler
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, configurable
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#define _MON_VERSION 100 // V x.yy
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, fixed
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#define _APP_SP_OFF_R0 0x00
|
||||
#define _APP_SP_OFF_R1 0x04
|
||||
#define _APP_SP_OFF_R2 0x08
|
||||
#define _APP_SP_OFF_R3 0x0C
|
||||
#define _APP_SP_OFF_R12 0x10
|
||||
#define _APP_SP_OFF_R14_LR 0x14
|
||||
#define _APP_SP_OFF_PC 0x18
|
||||
#define _APP_SP_OFF_XPSR 0x1C
|
||||
#define _APP_SP_OFF_S0 0x20
|
||||
#define _APP_SP_OFF_S1 0x24
|
||||
#define _APP_SP_OFF_S2 0x28
|
||||
#define _APP_SP_OFF_S3 0x2C
|
||||
#define _APP_SP_OFF_S4 0x30
|
||||
#define _APP_SP_OFF_S5 0x34
|
||||
#define _APP_SP_OFF_S6 0x38
|
||||
#define _APP_SP_OFF_S7 0x3C
|
||||
#define _APP_SP_OFF_S8 0x40
|
||||
#define _APP_SP_OFF_S9 0x44
|
||||
#define _APP_SP_OFF_S10 0x48
|
||||
#define _APP_SP_OFF_S11 0x4C
|
||||
#define _APP_SP_OFF_S12 0x50
|
||||
#define _APP_SP_OFF_S13 0x54
|
||||
#define _APP_SP_OFF_S14 0x58
|
||||
#define _APP_SP_OFF_S15 0x5C
|
||||
#define _APP_SP_OFF_FPSCR 0x60
|
||||
|
||||
#define _NUM_BYTES_BASIC_STACKFRAME 32
|
||||
#define _NUM_BYTES_EXTENDED_STACKFRAME 104 // Values for stackframes are explained at location where they are used
|
||||
|
||||
#define _SYSTEM_DCRDR_OFF 0x00
|
||||
#define _SYSTEM_DEMCR_OFF 0x04
|
||||
|
||||
#define _SYSTEM_DHCSR 0xE000EDF0 // Debug Halting Control and Status Register (DHCSR)
|
||||
#define _SYSTEM_DCRSR 0xE000EDF4 // Debug Core Register Selector Register (DCRSR)
|
||||
#define _SYSTEM_DCRDR 0xE000EDF8 // Debug Core Register Data Register (DCRDR)
|
||||
#define _SYSTEM_DEMCR 0xE000EDFC // Debug Exception and Monitor Control Register (DEMCR)
|
||||
|
||||
#define _SYSTEM_FPCCR 0xE000EF34 // Floating-Point Context Control Register (FPCCR)
|
||||
#define _SYSTEM_FPCAR 0xE000EF38 // Floating-Point Context Address Register (FPCAR)
|
||||
#define _SYSTEM_FPDSCR 0xE000EF3C // Floating-Point Default Status Control Register (FPDSCR)
|
||||
#define _SYSTEM_MVFR0 0xE000EF40 // Media and FP Feature Register 0 (MVFR0)
|
||||
#define _SYSTEM_MVFR1 0xE000EF44 // Media and FP Feature Register 1 (MVFR1)
|
||||
|
||||
/*
|
||||
* Defines for determining if the current debug config supports FPU registers
|
||||
* For some compilers like IAR EWARM when disabling the FPU in the compiler settings an error is thrown when
|
||||
*/
|
||||
#ifdef __FPU_PRESENT
|
||||
#if __FPU_PRESENT
|
||||
#define _HAS_FPU_REGS 1
|
||||
#else
|
||||
#define _HAS_FPU_REGS 0
|
||||
#endif
|
||||
#else
|
||||
#define _HAS_FPU_REGS 0
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Signature of monitor
|
||||
*
|
||||
* Function description
|
||||
* Needed for targets where also a boot ROM is present that possibly specifies a vector table with a valid debug monitor exception entry
|
||||
*/
|
||||
.section .text, "ax"
|
||||
|
||||
//
|
||||
// JLINKMONHANDLER
|
||||
//
|
||||
.byte 0x4A
|
||||
.byte 0x4C
|
||||
.byte 0x49
|
||||
.byte 0x4E
|
||||
.byte 0x4B
|
||||
.byte 0x4D
|
||||
.byte 0x4F
|
||||
.byte 0x4E
|
||||
.byte 0x48
|
||||
.byte 0x41
|
||||
.byte 0x4E
|
||||
.byte 0x44
|
||||
.byte 0x4C
|
||||
.byte 0x45
|
||||
.byte 0x52
|
||||
.byte 0x00 // Align to 8-bytes
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* DebugMon_Handler()
|
||||
*
|
||||
* Function description
|
||||
* Debug monitor handler. CPU enters this handler in case a "halt" request is made from the debugger.
|
||||
* This handler is also responsible for handling commands that are sent by the debugger.
|
||||
*
|
||||
* Notes
|
||||
* This is actually the ISR for the debug inerrupt (exception no. 12)
|
||||
*/
|
||||
.thumb_func
|
||||
|
||||
DebugMon_Handler:
|
||||
/*
|
||||
General procedure:
|
||||
DCRDR is used as communication register
|
||||
DEMCR[19] is used as ready flag
|
||||
For the command J-Link sends to the monitor: DCRDR[7:0] == Cmd, DCRDR[31:8] == ParamData
|
||||
|
||||
1) Monitor sets DEMCR[19] whenever it is ready to receive new commands/data
|
||||
DEMCR[19] is initially set on debug monitor entry
|
||||
2) J-Link will clear DEMCR[19] it has placed command/data in DCRDR for monitor
|
||||
3) Monitor will wait for DEMCR[19] to be cleared
|
||||
4) Monitor will process command (May cause additional data transfers etc., depends on command). Monitor will set DEMCR[19] whenever it has placed data for J-Link in the DCRDR
|
||||
5) No restart-CPU command? => Back to 2), Otherwise => 6)
|
||||
6) Monitor will clear DEMCR[19] 19 to indicate that it is no longer ready
|
||||
*/
|
||||
PUSH {LR}
|
||||
BL JLINK_MONITOR_OnEnter
|
||||
POP {LR}
|
||||
LDR.N R3,_AddrDCRDR // 0xe000edf8 == _SYSTEM_DCRDR
|
||||
B.N _IndicateMonReady
|
||||
_WaitProbeReadIndicateMonRdy: // while(_SYSTEM_DEMCR & (1uL << 19)); => Wait until J-Link has read item
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR
|
||||
LSLS R0,R0,#+12
|
||||
BMI.N _WaitProbeReadIndicateMonRdy
|
||||
_IndicateMonReady:
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR |= (1uL << 19); => Set MON_REQ bit, so J-Link knows monitor is ready to receive commands
|
||||
ORR R0,R0,#0x80000
|
||||
STR R0,[R3, #+_SYSTEM_DEMCR_OFF]
|
||||
/*
|
||||
During command loop:
|
||||
R0 = Tmp
|
||||
R1 = Tmp
|
||||
R2 = Tmp
|
||||
R3 = &_SYSTEM_DCRDR (allows also access to DEMCR with offset)
|
||||
R12 = Tmp
|
||||
|
||||
Outside command loop R0-R3 and R12 may be overwritten by MONITOR_OnPoll()
|
||||
*/
|
||||
_WaitForJLinkCmd: // do {
|
||||
PUSH {LR}
|
||||
BL JLINK_MONITOR_OnPoll
|
||||
POP {LR}
|
||||
LDR.N R3,_AddrDCRDR // 0xe000edf8 == _SYSTEM_DCRDR
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF]
|
||||
LSRS R0,R0,#+20 // DEMCR[19] -> Carry Clear? => J-Link has placed command for us
|
||||
BCS _WaitForJLinkCmd
|
||||
/*
|
||||
Perform command
|
||||
Command is placed by J-Link in DCRDR[7:0] and additional parameter data is stored in DCRDR[31:8]
|
||||
J-Link clears DEMCR[19] to indicate that it placed a command/data or read data
|
||||
Monitor sets DEMCR[19] to indicate that it placed data or read data / is ready for a new command
|
||||
Setting DEMCR[19] indicates "monitor ready for new command / data" and also indicates: "data has been placed in DCRDR by monitor, for J-Link"
|
||||
Therefore it is responsibility of the commands to respond to the commands accordingly
|
||||
|
||||
Commands for debug monitor
|
||||
Commands must not exceed 0xFF (255) as we only defined 8-bits for command-part. Higher 24-bits are parameter info for current command
|
||||
|
||||
Protocol for different commands:
|
||||
J-Link: Cmd -> DCRDR, DEMCR[19] -> 0 => Cmd placed by probe
|
||||
*/
|
||||
LDR R0,[R3, #+_SYSTEM_DCRDR_OFF] // ParamInfo = _SYSTEM_DCRDR
|
||||
LSRS R1,R0,#+8 // ParamInfo >>= 8
|
||||
LSLS R0,R0,#+24
|
||||
LSRS R0,R0,#+24 // Cmd = ParamInfo & 0xFF
|
||||
//
|
||||
// switch (Cmd)
|
||||
//
|
||||
CMP R0,#+0
|
||||
BEQ.N _HandleGetMonVersion // case _MON_CMD_GET_MONITOR_VERSION
|
||||
CMP R0,#+2
|
||||
BEQ.N _HandleReadReg // case _MON_CMD_READ_REG
|
||||
BCC.N _HandleRestartCPU // case _MON_CMD_RESTART_CPU
|
||||
CMP R0,#+3
|
||||
BEQ.N _HandleWriteReg_Veneer // case _MON_CMD_WRITE_REG
|
||||
B.N _IndicateMonReady // default : while (1);
|
||||
/*
|
||||
Return
|
||||
_MON_CMD_RESTART_CPU
|
||||
CPU: DEMCR[19] -> 0 => Monitor no longer ready
|
||||
*/
|
||||
_HandleRestartCPU:
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR &= ~(1uL << 19); => Clear MON_REQ to indicate that monitor is no longer active
|
||||
BIC R0,R0,#0x80000
|
||||
STR R0,[R3, #+_SYSTEM_DEMCR_OFF]
|
||||
PUSH {LR}
|
||||
BL JLINK_MONITOR_OnExit
|
||||
POP {PC}
|
||||
//
|
||||
// Place data section here to not get in trouble with load-offsets
|
||||
//
|
||||
.section .text, "ax", %progbits
|
||||
.align 2
|
||||
_AddrDCRDR:
|
||||
.long 0xE000EDF8
|
||||
_AddrCPACR:
|
||||
.long 0xE000ED88
|
||||
|
||||
.section .text, "ax"
|
||||
.thumb_func
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* _HandleGetMonVersion
|
||||
;*
|
||||
;*/
|
||||
_HandleGetMonVersion:
|
||||
/*
|
||||
_MON_CMD_GET_MONITOR_VERSION
|
||||
CPU: Data -> DCRDR, DEMCR[19] -> 1 => Data ready
|
||||
J-Link: DCRDR -> Read, DEMCR[19] -> 0 => Data read
|
||||
CPU: DEMCR[19] -> 1 => Mon ready
|
||||
*/
|
||||
MOVS R0,#+_MON_VERSION
|
||||
STR R0,[R3, #+_SYSTEM_DCRDR_OFF] // _SYSTEM_DCRDR = x
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR |= (1uL << 19); => Set MON_REQ bit, so J-Link knows monitor is ready to receive commands
|
||||
ORR R0,R0,#0x80000
|
||||
STR R0,[R3, #+_SYSTEM_DEMCR_OFF] // Indicate data ready
|
||||
B _WaitProbeReadIndicateMonRdy
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _HandleReadReg
|
||||
*
|
||||
*/
|
||||
_HandleWriteReg_Veneer:
|
||||
B.N _HandleWriteReg
|
||||
_HandleReadReg:
|
||||
/*
|
||||
_MON_CMD_READ_REG
|
||||
CPU: Data -> DCRDR, DEMCR[19] -> 1 => Data ready
|
||||
J-Link: DCRDR -> Read, DEMCR[19] -> 0 => Data read
|
||||
CPU: DEMCR[19] -> 1 => Mon ready
|
||||
|
||||
|
||||
Register indexes
|
||||
0-15: R0-R15 (13 == R13 reserved => is banked ... Has to be read as PSP / MSP. Decision has to be done by J-Link DLL side!)
|
||||
16: XPSR
|
||||
17: MSP
|
||||
18: PSP
|
||||
19: CFBP CONTROL/FAULTMASK/BASEPRI/PRIMASK (packed into 4 bytes of word. CONTROL = CFBP[31:24], FAULTMASK = CFBP[16:23], BASEPRI = CFBP[15:8], PRIMASK = CFBP[7:0]
|
||||
20: FPSCR
|
||||
21-52: FPS0-FPS31
|
||||
|
||||
|
||||
Register usage when entering this "subroutine":
|
||||
R0 Cmd
|
||||
R1 ParamInfo
|
||||
R2 ---
|
||||
R3 = &_SYSTEM_DCRDR (allows also access to DEMCR with offset)
|
||||
R12 ---
|
||||
|
||||
Table B1-9 EXC_RETURN definition of exception return behavior, with FP extension
|
||||
LR Return to Return SP Frame type
|
||||
---------------------------------------------------------
|
||||
0xFFFFFFE1 Handler mode. MSP Extended
|
||||
0xFFFFFFE9 Thread mode MSP Extended
|
||||
0xFFFFFFED Thread mode PSP Extended
|
||||
0xFFFFFFF1 Handler mode. MSP Basic
|
||||
0xFFFFFFF9 Thread mode MSP Basic
|
||||
0xFFFFFFFD Thread mode PSP Basic
|
||||
|
||||
So LR[2] == 1 => Return stack == PSP else MSP
|
||||
|
||||
R0-R3, R12, PC, xPSR can be read from application stackpointer
|
||||
Other regs can be read directly
|
||||
*/
|
||||
LSRS R2,LR,#+3 // Shift LR[2] into carry => Carry clear means that CPU was running on MSP
|
||||
ITE CS
|
||||
MRSCS R2,PSP
|
||||
MRSCC R2,MSP
|
||||
CMP R1,#+4 // if (RegIndex < 4) { (R0-R3)
|
||||
BCS _HandleReadRegR4
|
||||
LDR R0,[R2, R1, LSL #+2] // v = [SP + Rx * 4] (R0-R3)
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR4:
|
||||
CMP R1,#+5 // if (RegIndex < 5) { (R4)
|
||||
BCS _HandleReadRegR5
|
||||
MOV R0,R4
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR5:
|
||||
CMP R1,#+6 // if (RegIndex < 6) { (R5)
|
||||
BCS _HandleReadRegR6
|
||||
MOV R0,R5
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR6:
|
||||
CMP R1,#+7 // if (RegIndex < 7) { (R6)
|
||||
BCS _HandleReadRegR7
|
||||
MOV R0,R6
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR7:
|
||||
CMP R1,#+8 // if (RegIndex < 8) { (R7)
|
||||
BCS _HandleReadRegR8
|
||||
MOV R0,R7
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR8:
|
||||
CMP R1,#+9 // if (RegIndex < 9) { (R8)
|
||||
BCS _HandleReadRegR9
|
||||
MOV R0,R8
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR9:
|
||||
CMP R1,#+10 // if (RegIndex < 10) { (R9)
|
||||
BCS _HandleReadRegR10
|
||||
MOV R0,R9
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR10:
|
||||
CMP R1,#+11 // if (RegIndex < 11) { (R10)
|
||||
BCS _HandleReadRegR11
|
||||
MOV R0,R10
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR11:
|
||||
CMP R1,#+12 // if (RegIndex < 12) { (R11)
|
||||
BCS _HandleReadRegR12
|
||||
MOV R0,R11
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR12:
|
||||
CMP R1,#+14 // if (RegIndex < 14) { (R12)
|
||||
BCS _HandleReadRegR14
|
||||
LDR R0,[R2, #+_APP_SP_OFF_R12]
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR14:
|
||||
CMP R1,#+15 // if (RegIndex < 15) { (R14 / LR)
|
||||
BCS _HandleReadRegR15
|
||||
LDR R0,[R2, #+_APP_SP_OFF_R14_LR]
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR15:
|
||||
CMP R1,#+16 // if (RegIndex < 16) { (R15 / PC)
|
||||
BCS _HandleReadRegXPSR
|
||||
LDR R0,[R2, #+_APP_SP_OFF_PC]
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegXPSR:
|
||||
CMP R1,#+17 // if (RegIndex < 17) { (xPSR)
|
||||
BCS _HandleReadRegMSP
|
||||
LDR R0,[R2, #+_APP_SP_OFF_XPSR]
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegMSP:
|
||||
/*
|
||||
Stackpointer is tricky because we need to get some info about the SP used in the user app, first
|
||||
|
||||
Handle reading R0-R3 which can be read right from application stackpointer
|
||||
|
||||
Table B1-9 EXC_RETURN definition of exception return behavior, with FP extension
|
||||
LR Return to Return SP Frame type
|
||||
---------------------------------------------------------
|
||||
0xFFFFFFE1 Handler mode. MSP Extended
|
||||
0xFFFFFFE9 Thread mode MSP Extended
|
||||
0xFFFFFFED Thread mode PSP Extended
|
||||
0xFFFFFFF1 Handler mode. MSP Basic
|
||||
0xFFFFFFF9 Thread mode MSP Basic
|
||||
0xFFFFFFFD Thread mode PSP Basic
|
||||
|
||||
So LR[2] == 1 => Return stack == PSP else MSP
|
||||
Per architecture definition: Inside monitor (exception) SP = MSP
|
||||
|
||||
Stack pointer handling is complicated because it is different what is pushed on the stack before entering the monitor ISR...
|
||||
Cortex-M: 8 regs
|
||||
Cortex-M + forced-stack-alignment: 8 regs + 1 dummy-word if stack was not 8-byte aligned
|
||||
Cortex-M + FPU: 8 regs + 17 FPU regs + 1 dummy-word + 1-dummy word if stack was not 8-byte aligned
|
||||
Cortex-M + FPU + lazy mode: 8 regs + 17 dummy-words + 1 dummy-word + 1-dummy word if stack was not 8-byte aligned
|
||||
*/
|
||||
CMP R1,#+18 // if (RegIndex < 18) { (MSP)
|
||||
BCS _HandleReadRegPSP
|
||||
MRS R0,MSP
|
||||
LSRS R1,LR,#+3 // LR[2] -> Carry == 0 => CPU was running on MSP => Needs correction
|
||||
BCS _HandleReadRegDone_Veneer // CPU was running on PSP? => No correction necessary
|
||||
_HandleSPCorrection:
|
||||
LSRS R1,LR,#+5 // LR[4] -> Carry == 0 => extended stack frame has been allocated. See ARM DDI0403D, B1.5.7 Stack alignment on exception entry
|
||||
ITE CS
|
||||
ADDCS R0,R0,#+_NUM_BYTES_BASIC_STACKFRAME
|
||||
ADDCC R0,R0,#+_NUM_BYTES_EXTENDED_STACKFRAME
|
||||
LDR R1,[R2, #+_APP_SP_OFF_XPSR] // Get xPSR from application stack (R2 has been set to app stack on beginning of _HandleReadReg)
|
||||
LSRS R1,R1,#+5 // xPSR[9] -> Carry == 1 => Stack has been force-aligned before pushing regs. See ARM DDI0403D, B1.5.7 Stack alignment on exception entry
|
||||
IT CS
|
||||
ADDCS R0,R0,#+4
|
||||
B _HandleReadRegDone
|
||||
_HandleReadRegPSP: // RegIndex == 18
|
||||
CMP R1,#+19 // if (RegIndex < 19) {
|
||||
BCS _HandleReadRegCFBP
|
||||
MRS R0,PSP // PSP is not touched by monitor
|
||||
LSRS R1,LR,#+3 // LR[2] -> Carry == 1 => CPU was running on PSP => Needs correction
|
||||
BCC _HandleReadRegDone_Veneer // CPU was running on MSP? => No correction of PSP necessary
|
||||
B _HandleSPCorrection
|
||||
_HandleReadRegCFBP:
|
||||
/*
|
||||
CFBP is a register that can only be read via debug probe and is a merger of the following regs:
|
||||
CONTROL/FAULTMASK/BASEPRI/PRIMASK (packed into 4 bytes of word. CONTROL = CFBP[31:24], FAULTMASK = CFBP[16:23], BASEPRI = CFBP[15:8], PRIMASK = CFBP[7:0]
|
||||
To keep J-Link side the same for monitor and halt mode, we also return CFBP in monitor mode
|
||||
*/
|
||||
CMP R1,#+20 // if (RegIndex < 20) { (CFBP)
|
||||
BCS _HandleReadRegFPU
|
||||
MOVS R0,#+0
|
||||
MRS R2,PRIMASK
|
||||
ORRS R0,R2 // Merge PRIMASK into CFBP[7:0]
|
||||
MRS R2,BASEPRI
|
||||
LSLS R2,R2,#+8 // Merge BASEPRI into CFBP[15:8]
|
||||
ORRS R0,R2
|
||||
MRS R2,FAULTMASK
|
||||
LSLS R2,R2,#+16 // Merge FAULTMASK into CFBP[23:16]
|
||||
ORRS R0,R2
|
||||
MRS R2,CONTROL
|
||||
LSRS R1,LR,#3 // LR[2] -> Carry. CONTROL.SPSEL is saved to LR[2] on exception entry => ARM DDI0403D, B1.5.6 Exception entry behavior
|
||||
IT CS // As J-Link sees value of CONTROL at application time, we need reconstruct original value of CONTROL
|
||||
ORRCS R2,R2,#+2 // CONTROL.SPSEL (CONTROL[1]) == 0 inside monitor
|
||||
LSRS R1,LR,#+5 // LR[4] == NOT(CONTROL.FPCA) -> Carry
|
||||
ITE CS // Merge original value of FPCA (CONTROL[2]) into read data
|
||||
BICCS R2,R2,#+0x04 // Remember LR contains NOT(CONTROL)
|
||||
ORRCC R2,R2,#+0x04
|
||||
LSLS R2,R2,#+24
|
||||
ORRS R0,R2
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegFPU:
|
||||
#if _HAS_FPU_REGS
|
||||
CMP R1,#+53 // if (RegIndex < 53) { (20 (FPSCR), 21-52 FPS0-FPS31)
|
||||
BCS _HandleReadRegDone_Veneer
|
||||
/*
|
||||
Read Coprocessor Access Control Register (CPACR) to check if CP10 and CP11 are enabled
|
||||
If not, access to floating point is not possible
|
||||
CPACR[21:20] == CP10 enable. 0b01 = Privileged access only. 0b11 = Full access. Other = reserved
|
||||
CPACR[23:22] == CP11 enable. 0b01 = Privileged access only. 0b11 = Full access. Other = reserved
|
||||
*/
|
||||
LDR R0,_AddrCPACR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+8
|
||||
LSRS R0,R0,#+28
|
||||
CMP R0,#+0xF
|
||||
BEQ _HandleReadRegFPU_Allowed
|
||||
CMP R0,#+0x5
|
||||
BNE _HandleReadRegDone_Veneer
|
||||
_HandleReadRegFPU_Allowed:
|
||||
CMP R1,#+21 // if (RegIndex < 21) (20 == FPSCR)
|
||||
BCS _HandleReadRegFPS0_FPS31
|
||||
LSRS R0,LR,#+5 // CONTROL[2] == FPCA => NOT(FPCA) saved to LR[4]. LR[4] == 0 => Extended stack frame, so FPU regs possibly on stack
|
||||
BCS _HandleReadFPSCRLazyMode // Remember: NOT(FPCA) is stored to LR. == 0 means: Extended stack frame
|
||||
LDR R0,=_SYSTEM_FPCCR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+2 // FPCCR[30] -> Carry == 1 indicates if lazy mode is active, so space on stack is reserved but FPU registers are not saved on stack
|
||||
BCS _HandleReadFPSCRLazyMode
|
||||
LDR R0,[R2, #+_APP_SP_OFF_FPSCR]
|
||||
B _HandleReadRegDone
|
||||
_HandleReadFPSCRLazyMode:
|
||||
VMRS R0,FPSCR
|
||||
B _HandleReadRegDone
|
||||
_HandleReadRegFPS0_FPS31: // RegIndex == 21-52
|
||||
LSRS R0,LR,#+5 // CONTROL[2] == FPCA => NOT(FPCA) saved to LR[4]. LR[4] == 0 => Extended stack frame, so FPU regs possibly on stack
|
||||
BCS _HandleReadFPS0_FPS31LazyMode // Remember: NOT(FPCA) is stored to LR. == 0 means: Extended stack frame
|
||||
LDR R0,=_SYSTEM_FPCCR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+2 // FPCCR[30] -> Carry == 1 indicates if lazy mode is active, so space on stack is reserved but FPU registers are not saved on stack
|
||||
BCS _HandleReadFPS0_FPS31LazyMode
|
||||
SUBS R1,#+21 // Convert absolute reg index into rel. one
|
||||
LSLS R1,R1,#+2 // RegIndex to position on stack
|
||||
ADDS R1,#+_APP_SP_OFF_S0
|
||||
LDR R0,[R2, R1]
|
||||
_HandleReadRegDone_Veneer:
|
||||
B _HandleReadRegDone
|
||||
_HandleReadFPS0_FPS31LazyMode:
|
||||
SUBS R1,#+20 // convert abs. RegIndex into rel. one
|
||||
MOVS R0,#+6
|
||||
MULS R1,R0,R1
|
||||
LDR R0,=_HandleReadRegUnknown
|
||||
SUB R0,R0,R1 // _HandleReadRegUnknown - 6 * ((RegIndex - 21) + 1)
|
||||
ORR R0,R0,#1 // Thumb bit needs to be set in DestAddr
|
||||
BX R0
|
||||
//
|
||||
// Table for reading FPS0-FPS31
|
||||
//
|
||||
VMOV R0,S31 // v = FPSx
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S30
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S29
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S28
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S27
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S26
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S25
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S24
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S23
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S22
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S21
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S20
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S19
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S18
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S17
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S16
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S15
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S14
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S13
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S12
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S11
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S10
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S9
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S8
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S7
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S6
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S5
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S4
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S3
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S2
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S1
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S0
|
||||
B _HandleReadRegDone
|
||||
#else
|
||||
B _HandleReadRegUnknown
|
||||
_HandleReadRegDone_Veneer:
|
||||
B _HandleReadRegDone
|
||||
#endif
|
||||
_HandleReadRegUnknown:
|
||||
MOVS R0,#+0 // v = 0
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegDone:
|
||||
|
||||
// Send register content to J-Link and wait until J-Link has read the data
|
||||
|
||||
STR R0,[R3, #+_SYSTEM_DCRDR_OFF] // DCRDR = v;
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR |= (1uL << 19); => Set MON_REQ bit, so J-Link knows monitor is ready to receive commands
|
||||
ORR R0,R0,#0x80000
|
||||
STR R0,[R3, #+_SYSTEM_DEMCR_OFF] // Indicate data ready
|
||||
B _WaitProbeReadIndicateMonRdy
|
||||
|
||||
// Data section for register addresses
|
||||
|
||||
_HandleWriteReg:
|
||||
/*
|
||||
_MON_CMD_WRITE_REG
|
||||
CPU: DEMCR[19] -> 1 => Mon ready
|
||||
J-Link: Data -> DCRDR, DEMCR[19] -> 0 => Data placed by probe
|
||||
CPU: DCRDR -> Read, Process command, DEMCR[19] -> 1 => Data read & mon ready
|
||||
|
||||
Register indexes
|
||||
0-15: R0-R15 (13 == R13 reserved => is banked ... Has to be read as PSP / MSP. Decision has to be done by J-Link DLL side!)
|
||||
16: XPSR
|
||||
17: MSP
|
||||
18: PSP
|
||||
19: CFBP CONTROL/FAULTMASK/BASEPRI/PRIMASK (packed into 4 bytes of word. CONTROL = CFBP[31:24], FAULTMASK = CFBP[16:23], BASEPRI = CFBP[15:8], PRIMASK = CFBP[7:0]
|
||||
20: FPSCR
|
||||
21-52: FPS0-FPS31
|
||||
|
||||
|
||||
Register usage when entering this "subroutine":
|
||||
R0 Cmd
|
||||
R1 ParamInfo
|
||||
R2 ---
|
||||
R3 = &_SYSTEM_DCRDR (allows also access to DEMCR with offset)
|
||||
R12 ---
|
||||
|
||||
Table B1-9 EXC_RETURN definition of exception return behavior, with FP extension
|
||||
LR Return to Return SP Frame type
|
||||
---------------------------------------------------------
|
||||
0xFFFFFFE1 Handler mode. MSP Extended
|
||||
0xFFFFFFE9 Thread mode MSP Extended
|
||||
0xFFFFFFED Thread mode PSP Extended
|
||||
0xFFFFFFF1 Handler mode. MSP Basic
|
||||
0xFFFFFFF9 Thread mode MSP Basic
|
||||
0xFFFFFFFD Thread mode PSP Basic
|
||||
|
||||
So LR[2] == 1 => Return stack == PSP else MSP
|
||||
|
||||
R0-R3, R12, PC, xPSR can be written via application stackpointer
|
||||
Other regs can be written directly
|
||||
|
||||
|
||||
Read register data from J-Link into R0
|
||||
*/
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR |= (1uL << 19); => Monitor is ready to receive register data
|
||||
ORR R0,R0,#0x80000
|
||||
STR R0,[R3, #+_SYSTEM_DEMCR_OFF]
|
||||
_HandleWRegWaitUntilDataRecv:
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF]
|
||||
LSLS R0,R0,#+12
|
||||
BMI.N _HandleWRegWaitUntilDataRecv // DEMCR[19] == 0 => J-Link has placed new data for us
|
||||
LDR R0,[R3, #+_SYSTEM_DCRDR_OFF] // Get register data
|
||||
//
|
||||
// Determine application SP
|
||||
//
|
||||
LSRS R2,LR,#+3 // Shift LR[2] into carry => Carry clear means that CPU was running on MSP
|
||||
ITE CS
|
||||
MRSCS R2,PSP
|
||||
MRSCC R2,MSP
|
||||
CMP R1,#+4 // if (RegIndex < 4) { (R0-R3)
|
||||
BCS _HandleWriteRegR4
|
||||
STR R0,[R2, R1, LSL #+2] // v = [SP + Rx * 4] (R0-R3)
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR4:
|
||||
CMP R1,#+5 // if (RegIndex < 5) { (R4)
|
||||
BCS _HandleWriteRegR5
|
||||
MOV R4,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR5:
|
||||
CMP R1,#+6 // if (RegIndex < 6) { (R5)
|
||||
BCS _HandleWriteRegR6
|
||||
MOV R5,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR6:
|
||||
CMP R1,#+7 // if (RegIndex < 7) { (R6)
|
||||
BCS _HandleWriteRegR7
|
||||
MOV R6,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR7:
|
||||
CMP R1,#+8 // if (RegIndex < 8) { (R7)
|
||||
BCS _HandleWriteRegR8
|
||||
MOV R7,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR8:
|
||||
CMP R1,#+9 // if (RegIndex < 9) { (R8)
|
||||
BCS _HandleWriteRegR9
|
||||
MOV R8,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR9:
|
||||
CMP R1,#+10 // if (RegIndex < 10) { (R9)
|
||||
BCS _HandleWriteRegR10
|
||||
MOV R9,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR10:
|
||||
CMP R1,#+11 // if (RegIndex < 11) { (R10)
|
||||
BCS _HandleWriteRegR11
|
||||
MOV R10,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR11:
|
||||
CMP R1,#+12 // if (RegIndex < 12) { (R11)
|
||||
BCS _HandleWriteRegR12
|
||||
MOV R11,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR12:
|
||||
CMP R1,#+14 // if (RegIndex < 14) { (R12)
|
||||
BCS _HandleWriteRegR14
|
||||
STR R0,[R2, #+_APP_SP_OFF_R12]
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR14:
|
||||
CMP R1,#+15 // if (RegIndex < 15) { (R14 / LR)
|
||||
BCS _HandleWriteRegR15
|
||||
STR R0,[R2, #+_APP_SP_OFF_R14_LR]
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR15:
|
||||
CMP R1,#+16 // if (RegIndex < 16) { (R15 / PC)
|
||||
BCS _HandleWriteRegXPSR
|
||||
STR R0,[R2, #+_APP_SP_OFF_PC]
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegXPSR:
|
||||
CMP R1,#+17 // if (RegIndex < 17) { (xPSR)
|
||||
BCS _HandleWriteRegMSP
|
||||
STR R0,[R2, #+_APP_SP_OFF_XPSR]
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegMSP:
|
||||
//
|
||||
// For now, SP cannot be modified because it is needed to jump back from monitor mode
|
||||
//
|
||||
CMP R1,#+18 // if (RegIndex < 18) { (MSP)
|
||||
BCS _HandleWriteRegPSP
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegPSP: // RegIndex == 18
|
||||
CMP R1,#+19 // if (RegIndex < 19) {
|
||||
BCS _HandleWriteRegCFBP
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegCFBP:
|
||||
/*
|
||||
CFBP is a register that can only be read via debug probe and is a merger of the following regs:
|
||||
CONTROL/FAULTMASK/BASEPRI/PRIMASK (packed into 4 bytes of word. CONTROL = CFBP[31:24], FAULTMASK = CFBP[16:23], BASEPRI = CFBP[15:8], PRIMASK = CFBP[7:0]
|
||||
To keep J-Link side the same for monitor and halt mode, we also return CFBP in monitor mode
|
||||
*/
|
||||
CMP R1,#+20 // if (RegIndex < 20) { (CFBP)
|
||||
BCS _HandleWriteRegFPU
|
||||
LSLS R1,R0,#+24
|
||||
LSRS R1,R1,#+24 // Extract CFBP[7:0] => PRIMASK
|
||||
MSR PRIMASK,R1
|
||||
LSLS R1,R0,#+16
|
||||
LSRS R1,R1,#+24 // Extract CFBP[15:8] => BASEPRI
|
||||
MSR BASEPRI,R1
|
||||
LSLS R1,R0,#+8 // Extract CFBP[23:16] => FAULTMASK
|
||||
LSRS R1,R1,#+24
|
||||
MSR FAULTMASK,R1
|
||||
LSRS R1,R0,#+24 // Extract CFBP[31:24] => CONTROL
|
||||
LSRS R0,R1,#2 // Current CONTROL[1] -> Carry
|
||||
ITE CS // Update saved CONTROL.SPSEL (CONTROL[1]). CONTROL.SPSEL is saved to LR[2] on exception entry => ARM DDI0403D, B1.5.6 Exception entry behavior
|
||||
ORRCS LR,LR,#+4
|
||||
BICCC LR,LR,#+4
|
||||
BIC R1,R1,#+2 // CONTROL.SPSEL (CONTROL[1]) == 0 inside monitor. Otherwise behavior is UNPREDICTABLE
|
||||
LSRS R0,R1,#+3 // New CONTROL.FPCA (CONTROL[2]) -> Carry
|
||||
ITE CS // CONTROL[2] == FPCA => NOT(FPCA) saved to LR[4]. LR[4] == 0 => Extended stack frame, so FPU regs possibly on stack
|
||||
BICCS LR,LR,#+0x10 // Remember: NOT(FPCA) is stored to LR. == 0 means: Extended stack frame
|
||||
ORRCC LR,LR,#+0x10
|
||||
MRS R0,CONTROL
|
||||
LSRS R0,R0,#+3 // CONTROL[2] -> Carry
|
||||
ITE CS // Preserve original value of current CONTROL[2]
|
||||
ORRCS R1,R1,#+0x04
|
||||
BICCC R1,R1,#+0x04
|
||||
MSR CONTROL,R1
|
||||
ISB // Necessary after writing to CONTROL, see ARM DDI0403D, B1.4.4 The special-purpose CONTROL register
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegFPU:
|
||||
#if _HAS_FPU_REGS
|
||||
CMP R1,#+53 // if (RegIndex < 53) { (20 (FPSCR), 21-52 FPS0-FPS31)
|
||||
BCS _HandleWriteRegDone_Veneer
|
||||
/*
|
||||
Read Coprocessor Access Control Register (CPACR) to check if CP10 and CP11 are enabled
|
||||
If not, access to floating point is not possible
|
||||
CPACR[21:20] == CP10 enable. 0b01 = Privileged access only. 0b11 = Full access. Other = reserved
|
||||
CPACR[23:22] == CP11 enable. 0b01 = Privileged access only. 0b11 = Full access. Other = reserved
|
||||
*/
|
||||
MOV R12,R0 // Save register data
|
||||
LDR R0,_AddrCPACR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+8
|
||||
LSRS R0,R0,#+28
|
||||
CMP R0,#+0xF
|
||||
BEQ _HandleWriteRegFPU_Allowed
|
||||
CMP R0,#+0x5
|
||||
BNE _HandleWriteRegDone_Veneer
|
||||
_HandleWriteRegFPU_Allowed:
|
||||
CMP R1,#+21 // if (RegIndex < 21) (20 == FPSCR)
|
||||
BCS _HandleWriteRegFPS0_FPS31
|
||||
LSRS R0,LR,#+5 // CONTROL[2] == FPCA => NOT(FPCA) saved to LR[4]. LR[4] == 0 => Extended stack frame, so FPU regs possibly on stack
|
||||
BCS _HandleWriteFPSCRLazyMode // Remember: NOT(FPCA) is stored to LR. == 0 means: Extended stack frame
|
||||
LDR R0,=_SYSTEM_FPCCR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+2 // FPCCR[30] -> Carry == 1 indicates if lazy mode is active, so space on stack is reserved but FPU registers are not saved on stack
|
||||
BCS _HandleWriteFPSCRLazyMode
|
||||
STR R12,[R2, #+_APP_SP_OFF_FPSCR]
|
||||
B _HandleWriteRegDone
|
||||
_HandleWriteFPSCRLazyMode:
|
||||
VMSR FPSCR,R12
|
||||
B _HandleWriteRegDone
|
||||
_HandleWriteRegFPS0_FPS31: // RegIndex == 21-52
|
||||
LDR R0,=_SYSTEM_FPCCR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+2 // FPCCR[30] -> Carry == 1 indicates if lazy mode is active, so space on stack is reserved but FPU registers are not saved on stack
|
||||
BCS _HandleWriteFPS0_FPS31LazyMode
|
||||
LSRS R0,LR,#+5 // CONTROL[2] == FPCA => NOT(FPCA) saved to LR[4]. LR[4] == 0 => Extended stack frame, so FPU regs possibly on stack
|
||||
BCS _HandleWriteFPS0_FPS31LazyMode // Remember: NOT(FPCA) is stored to LR. == 0 means: Extended stack frame
|
||||
SUBS R1,#+21 // Convert absolute reg index into rel. one
|
||||
LSLS R1,R1,#+2 // RegIndex to position on stack
|
||||
ADDS R1,#+_APP_SP_OFF_S0
|
||||
STR R12,[R2, R1]
|
||||
_HandleWriteRegDone_Veneer:
|
||||
B _HandleWriteRegDone
|
||||
_HandleWriteFPS0_FPS31LazyMode:
|
||||
SUBS R1,#+20 // Convert abs. RegIndex into rel. one
|
||||
MOVS R0,#+6
|
||||
MULS R1,R0,R1
|
||||
LDR R0,=_HandleReadRegUnknown
|
||||
SUB R0,R0,R1 // _HandleReadRegUnknown - 6 * ((RegIndex - 21) + 1)
|
||||
ORR R0,R0,#1 // Thumb bit needs to be set in DestAddr
|
||||
BX R0
|
||||
//
|
||||
// Table for reading FPS0-FPS31
|
||||
//
|
||||
VMOV S31,R12 // v = FPSx
|
||||
B _HandleWriteRegDone
|
||||
VMOV S30,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S29,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S28,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S27,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S26,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S25,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S24,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S23,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S22,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S21,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S20,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S19,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S18,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S17,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S16,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S15,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S14,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S13,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S12,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S11,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S10,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S9,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S8,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S7,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S6,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S5,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S4,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S3,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S2,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S1,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S0,R12
|
||||
B _HandleWriteRegDone
|
||||
#else
|
||||
B _HandleWriteRegUnknown
|
||||
#endif
|
||||
_HandleWriteRegUnknown:
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegDone:
|
||||
B _IndicateMonReady // Indicate that monitor has read data, processed command and is ready for a new one
|
||||
.end
|
||||
/****** End Of File *************************************************/
|
280
core/embed/segger/SEGGER_MMD/SEGGER_HardFaultHandler.c
Normal file
280
core/embed/segger/SEGGER_MMD/SEGGER_HardFaultHandler.c
Normal file
@ -0,0 +1,280 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2014 - 2020 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* - Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* - Neither the name of SEGGER Microcontroller GmbH *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. *
|
||||
* IN NO EVENT SHALL SEGGER Microcontroller GmbH BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
----------------------------------------------------------------------
|
||||
File : SEGGER_HardFaultHandler.c
|
||||
Purpose : Generic SEGGER HardFault handler for Cortex-M
|
||||
Literature:
|
||||
[1] Analyzing HardFaults on Cortex-M CPUs (https://www.segger.com/downloads/appnotes/AN00016_AnalyzingHardFaultsOnCortexM.pdf)
|
||||
|
||||
Additional information:
|
||||
This HardFault handler enables user-friendly analysis of hard faults
|
||||
in debug configurations.
|
||||
If a release configuration requires a HardFault handler,
|
||||
a specific HardFault handler should be included instead,
|
||||
which for example issues a reset or lits an error LED.
|
||||
-------- END-OF-HEADER ---------------------------------------------
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#define SYSHND_CTRL (*(volatile unsigned int*) (0xE000ED24u)) // System Handler Control and State Register
|
||||
#define NVIC_MFSR (*(volatile unsigned char*) (0xE000ED28u)) // Memory Management Fault Status Register
|
||||
#define NVIC_BFSR (*(volatile unsigned char*) (0xE000ED29u)) // Bus Fault Status Register
|
||||
#define NVIC_UFSR (*(volatile unsigned short*)(0xE000ED2Au)) // Usage Fault Status Register
|
||||
#define NVIC_HFSR (*(volatile unsigned int*) (0xE000ED2Cu)) // Hard Fault Status Register
|
||||
#define NVIC_DFSR (*(volatile unsigned int*) (0xE000ED30u)) // Debug Fault Status Register
|
||||
#define NVIC_BFAR (*(volatile unsigned int*) (0xE000ED38u)) // Bus Fault Manage Address Register
|
||||
#define NVIC_AFSR (*(volatile unsigned int*) (0xE000ED3Cu)) // Auxiliary Fault Status Register
|
||||
|
||||
#ifndef DEBUG // Should be overwritten by project settings
|
||||
#define DEBUG (0) // in debug builds
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Prototypes
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void HardFaultHandler(unsigned int* pStack);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Static data
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#if DEBUG
|
||||
static volatile unsigned int _Continue; // Set this variable to 1 to run further
|
||||
|
||||
static struct {
|
||||
struct {
|
||||
volatile unsigned int r0; // Register R0
|
||||
volatile unsigned int r1; // Register R1
|
||||
volatile unsigned int r2; // Register R2
|
||||
volatile unsigned int r3; // Register R3
|
||||
volatile unsigned int r12; // Register R12
|
||||
volatile unsigned int lr; // Link register
|
||||
volatile unsigned int pc; // Program counter
|
||||
union {
|
||||
volatile unsigned int byte;
|
||||
struct {
|
||||
unsigned int IPSR : 8; // Interrupt Program Status register (IPSR)
|
||||
unsigned int EPSR : 19; // Execution Program Status register (EPSR)
|
||||
unsigned int APSR : 5; // Application Program Status register (APSR)
|
||||
} bits;
|
||||
} psr; // Program status register.
|
||||
} SavedRegs;
|
||||
|
||||
union {
|
||||
volatile unsigned int byte;
|
||||
struct {
|
||||
unsigned int MEMFAULTACT : 1; // Read as 1 if memory management fault is active
|
||||
unsigned int BUSFAULTACT : 1; // Read as 1 if bus fault exception is active
|
||||
unsigned int UnusedBits1 : 1;
|
||||
unsigned int USGFAULTACT : 1; // Read as 1 if usage fault exception is active
|
||||
unsigned int UnusedBits2 : 3;
|
||||
unsigned int SVCALLACT : 1; // Read as 1 if SVC exception is active
|
||||
unsigned int MONITORACT : 1; // Read as 1 if debug monitor exception is active
|
||||
unsigned int UnusedBits3 : 1;
|
||||
unsigned int PENDSVACT : 1; // Read as 1 if PendSV exception is active
|
||||
unsigned int SYSTICKACT : 1; // Read as 1 if SYSTICK exception is active
|
||||
unsigned int USGFAULTPENDED : 1; // Usage fault pended; usage fault started but was replaced by a higher-priority exception
|
||||
unsigned int MEMFAULTPENDED : 1; // Memory management fault pended; memory management fault started but was replaced by a higher-priority exception
|
||||
unsigned int BUSFAULTPENDED : 1; // Bus fault pended; bus fault handler was started but was replaced by a higher-priority exception
|
||||
unsigned int SVCALLPENDED : 1; // SVC pended; SVC was started but was replaced by a higher-priority exception
|
||||
unsigned int MEMFAULTENA : 1; // Memory management fault handler enable
|
||||
unsigned int BUSFAULTENA : 1; // Bus fault handler enable
|
||||
unsigned int USGFAULTENA : 1; // Usage fault handler enable
|
||||
} bits;
|
||||
} syshndctrl; // System Handler Control and State Register (0xE000ED24)
|
||||
|
||||
union {
|
||||
volatile unsigned char byte;
|
||||
struct {
|
||||
unsigned char IACCVIOL : 1; // Instruction access violation
|
||||
unsigned char DACCVIOL : 1; // Data access violation
|
||||
unsigned char UnusedBits : 1;
|
||||
unsigned char MUNSTKERR : 1; // Unstacking error
|
||||
unsigned char MSTKERR : 1; // Stacking error
|
||||
unsigned char UnusedBits2 : 2;
|
||||
unsigned char MMARVALID : 1; // Indicates the MMAR is valid
|
||||
} bits;
|
||||
} mfsr; // Memory Management Fault Status Register (0xE000ED28)
|
||||
|
||||
union {
|
||||
volatile unsigned int byte;
|
||||
struct {
|
||||
unsigned int IBUSERR : 1; // Instruction access violation
|
||||
unsigned int PRECISERR : 1; // Precise data access violation
|
||||
unsigned int IMPREISERR : 1; // Imprecise data access violation
|
||||
unsigned int UNSTKERR : 1; // Unstacking error
|
||||
unsigned int STKERR : 1; // Stacking error
|
||||
unsigned int UnusedBits : 2;
|
||||
unsigned int BFARVALID : 1; // Indicates BFAR is valid
|
||||
} bits;
|
||||
} bfsr; // Bus Fault Status Register (0xE000ED29)
|
||||
volatile unsigned int bfar; // Bus Fault Manage Address Register (0xE000ED38)
|
||||
|
||||
union {
|
||||
volatile unsigned short byte;
|
||||
struct {
|
||||
unsigned short UNDEFINSTR : 1; // Attempts to execute an undefined instruction
|
||||
unsigned short INVSTATE : 1; // Attempts to switch to an invalid state (e.g., ARM)
|
||||
unsigned short INVPC : 1; // Attempts to do an exception with a bad value in the EXC_RETURN number
|
||||
unsigned short NOCP : 1; // Attempts to execute a coprocessor instruction
|
||||
unsigned short UnusedBits : 4;
|
||||
unsigned short UNALIGNED : 1; // Indicates that an unaligned access fault has taken place
|
||||
unsigned short DIVBYZERO : 1; // Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)
|
||||
} bits;
|
||||
} ufsr; // Usage Fault Status Register (0xE000ED2A)
|
||||
|
||||
union {
|
||||
volatile unsigned int byte;
|
||||
struct {
|
||||
unsigned int UnusedBits : 1;
|
||||
unsigned int VECTBL : 1; // Indicates hard fault is caused by failed vector fetch
|
||||
unsigned int UnusedBits2 : 28;
|
||||
unsigned int FORCED : 1; // Indicates hard fault is taken because of bus fault/memory management fault/usage fault
|
||||
unsigned int DEBUGEVT : 1; // Indicates hard fault is triggered by debug event
|
||||
} bits;
|
||||
} hfsr; // Hard Fault Status Register (0xE000ED2C)
|
||||
|
||||
union {
|
||||
volatile unsigned int byte;
|
||||
struct {
|
||||
unsigned int HALTED : 1; // Halt requested in NVIC
|
||||
unsigned int BKPT : 1; // BKPT instruction executed
|
||||
unsigned int DWTTRAP : 1; // DWT match occurred
|
||||
unsigned int VCATCH : 1; // Vector fetch occurred
|
||||
unsigned int EXTERNAL : 1; // EDBGRQ signal asserted
|
||||
} bits;
|
||||
} dfsr; // Debug Fault Status Register (0xE000ED30)
|
||||
|
||||
volatile unsigned int afsr; // Auxiliary Fault Status Register (0xE000ED3C), Vendor controlled (optional)
|
||||
} HardFaultRegs;
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Global functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* HardFaultHandler()
|
||||
*
|
||||
* Function description
|
||||
* C part of the hard fault handler which is called by the assembler
|
||||
* function HardFault_Handler
|
||||
*/
|
||||
void HardFaultHandler(unsigned int* pStack) {
|
||||
//
|
||||
// In case we received a hard fault because of a breakpoint instruction, we return.
|
||||
// This may happen when using semihosting for printf outputs and no debugger is connected,
|
||||
// i.e. when running a "Debug" configuration in release mode.
|
||||
//
|
||||
if (NVIC_HFSR & (1u << 31)) {
|
||||
NVIC_HFSR |= (1u << 31); // Reset Hard Fault status
|
||||
*(pStack + 6u) += 2u; // PC is located on stack at SP + 24 bytes. Increment PC by 2 to skip break instruction.
|
||||
return; // Return to interrupted application
|
||||
}
|
||||
#if DEBUG
|
||||
//
|
||||
// Read NVIC registers
|
||||
//
|
||||
HardFaultRegs.syshndctrl.byte = SYSHND_CTRL; // System Handler Control and State Register
|
||||
HardFaultRegs.mfsr.byte = NVIC_MFSR; // Memory Fault Status Register
|
||||
HardFaultRegs.bfsr.byte = NVIC_BFSR; // Bus Fault Status Register
|
||||
HardFaultRegs.bfar = NVIC_BFAR; // Bus Fault Manage Address Register
|
||||
HardFaultRegs.ufsr.byte = NVIC_UFSR; // Usage Fault Status Register
|
||||
HardFaultRegs.hfsr.byte = NVIC_HFSR; // Hard Fault Status Register
|
||||
HardFaultRegs.dfsr.byte = NVIC_DFSR; // Debug Fault Status Register
|
||||
HardFaultRegs.afsr = NVIC_AFSR; // Auxiliary Fault Status Register
|
||||
//
|
||||
// Halt execution
|
||||
// If NVIC registers indicate readable memory, change the variable value to != 0 to continue execution.
|
||||
//
|
||||
_Continue = 0u;
|
||||
while (_Continue == 0u) {
|
||||
}
|
||||
//
|
||||
// Read saved registers from the stack.
|
||||
//
|
||||
HardFaultRegs.SavedRegs.r0 = pStack[0]; // Register R0
|
||||
HardFaultRegs.SavedRegs.r1 = pStack[1]; // Register R1
|
||||
HardFaultRegs.SavedRegs.r2 = pStack[2]; // Register R2
|
||||
HardFaultRegs.SavedRegs.r3 = pStack[3]; // Register R3
|
||||
HardFaultRegs.SavedRegs.r12 = pStack[4]; // Register R12
|
||||
HardFaultRegs.SavedRegs.lr = pStack[5]; // Link register LR
|
||||
HardFaultRegs.SavedRegs.pc = pStack[6]; // Program counter PC
|
||||
HardFaultRegs.SavedRegs.psr.byte = pStack[7]; // Program status word PSR
|
||||
//
|
||||
// Halt execution
|
||||
// To step out of the HardFaultHandler, change the variable value to != 0.
|
||||
//
|
||||
_Continue = 0u;
|
||||
while (_Continue == 0u) {
|
||||
}
|
||||
#else
|
||||
//
|
||||
// If this module is included in a release configuration, simply stay in the HardFault handler
|
||||
//
|
||||
(void)pStack;
|
||||
do {
|
||||
} while (1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************** End of file ****************************/
|
@ -12,6 +12,7 @@
|
||||
#define USE_RGB_COLORS 1
|
||||
#define USE_BACKLIGHT 1
|
||||
#define USE_DISP_I8080_16BIT_DW 1
|
||||
#define USE_BLE 1
|
||||
|
||||
#define DISPLAY_PANEL_INIT_SEQ lhs200kb_if21_init_seq
|
||||
#define DISPLAY_PANEL_ROTATE lhs200kb_if21_rotate
|
||||
|
24
core/embed/trezorhal/boards/trezor_t3w1_d1_NRF.h
Normal file
24
core/embed/trezorhal/boards/trezor_t3w1_d1_NRF.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef _TREZOR_T3W1_H
|
||||
#define _TREZOR_T3W1_H
|
||||
|
||||
// settings for nrf52
|
||||
#define SPI_SCK_PIN 14
|
||||
#define SPI_MISO_PIN 15
|
||||
#define SPI_MOSI_PIN 16
|
||||
#define SPI_SS_PIN 13
|
||||
|
||||
#define RX_PIN_NUMBER 26
|
||||
#define TX_PIN_NUMBER 27
|
||||
#define CTS_PIN_NUMBER 6
|
||||
#define RTS_PIN_NUMBER 8
|
||||
|
||||
#define LED_ORANGE_PIN 22
|
||||
#define LED_GREEN_PIN 24
|
||||
#define BUTTON_USER_PIN 21
|
||||
|
||||
#define STAY_BLD_PIN 40
|
||||
#define GPIO_1_PIN 28
|
||||
#define GPIO_2_PIN 29
|
||||
#define GPIO_3_PIN 30
|
||||
|
||||
#endif //_TREZOR_T3W1_H
|
438
core/embed/trezorhal/stm32f4/ble_hal.c
Normal file
438
core/embed/trezorhal/stm32f4/ble_hal.c
Normal file
@ -0,0 +1,438 @@
|
||||
/*
|
||||
* 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 STM32_HAL_H
|
||||
#include TREZOR_BOARD
|
||||
|
||||
#include "ble_hal.h"
|
||||
#include <string.h>
|
||||
#include "ble/int_comm_defs.h"
|
||||
#include "ble/messages.h"
|
||||
#include "ble/state.h"
|
||||
#include "buffers.h"
|
||||
#include "irq.h"
|
||||
#include "supervise.h"
|
||||
|
||||
#define SPI_QUEUE_SIZE 16
|
||||
|
||||
static UART_HandleTypeDef urt;
|
||||
|
||||
static SPI_HandleTypeDef spi = {0};
|
||||
static DMA_HandleTypeDef spi_dma = {0};
|
||||
|
||||
typedef struct {
|
||||
uint8_t buffer[BLE_PACKET_SIZE];
|
||||
bool used;
|
||||
bool ready;
|
||||
} spi_buffer_t;
|
||||
|
||||
BUFFER_SECTION spi_buffer_t spi_queue[SPI_QUEUE_SIZE];
|
||||
static int head = 0, tail = 0;
|
||||
static bool overrun = false;
|
||||
volatile uint16_t overrun_count = 0;
|
||||
volatile uint16_t msg_cntr = 0;
|
||||
volatile uint16_t first_overrun_at = 0;
|
||||
|
||||
static uint8_t int_comm_buffer[USB_DATA_SIZE];
|
||||
static uint16_t int_comm_msg_len = 0;
|
||||
static uint8_t int_event_buffer[USB_DATA_SIZE];
|
||||
static uint16_t int_event_msg_len = 0;
|
||||
|
||||
static bool g_comm_running = false;
|
||||
|
||||
void ble_comm_init(void) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
// synchronization signals
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_12;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = GPIO_1_PIN;
|
||||
HAL_GPIO_Init(GPIO_1_PORT, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Alternate = 0;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = GPIO_2_PIN;
|
||||
HAL_GPIO_Init(GPIO_2_PORT, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = GPIO_3_PIN;
|
||||
HAL_GPIO_Init(GPIO_3_PORT, &GPIO_InitStructure);
|
||||
|
||||
__HAL_RCC_USART1_CLK_ENABLE();
|
||||
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF7_USART1;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
urt.Init.Mode = UART_MODE_TX_RX;
|
||||
urt.Init.BaudRate = 1000000;
|
||||
urt.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS;
|
||||
urt.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
urt.Init.Parity = UART_PARITY_NONE, urt.Init.StopBits = UART_STOPBITS_1;
|
||||
urt.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
urt.Instance = USART1;
|
||||
|
||||
HAL_UART_Init(&urt);
|
||||
|
||||
__HAL_RCC_DMA2_CLK_ENABLE();
|
||||
__HAL_RCC_SPI1_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF5_SPI1;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_5;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
// GPIO_InitStructure.Pin = GPIO_PIN_9;
|
||||
// HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
spi_dma.Init.Channel = DMA_CHANNEL_3;
|
||||
spi_dma.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
spi_dma.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
spi_dma.Init.MemInc = DMA_MINC_ENABLE;
|
||||
spi_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
spi_dma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
spi_dma.Init.Mode = DMA_NORMAL;
|
||||
spi_dma.Init.Priority = DMA_PRIORITY_LOW;
|
||||
spi_dma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
spi_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||
spi_dma.Init.MemBurst = DMA_MBURST_SINGLE;
|
||||
spi_dma.Init.PeriphBurst = DMA_PBURST_SINGLE;
|
||||
spi_dma.Instance = DMA2_Stream0;
|
||||
HAL_DMA_Init(&spi_dma);
|
||||
|
||||
spi.Instance = SPI1;
|
||||
spi.Init.Mode = SPI_MODE_SLAVE;
|
||||
spi.Init.Direction = SPI_DIRECTION_2LINES; // rx only?
|
||||
spi.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
spi.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
spi.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
spi.Init.NSS = SPI_NSS_HARD_INPUT;
|
||||
spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
|
||||
spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
spi.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
spi.Init.CRCPolynomial = 0;
|
||||
spi.hdmarx = &spi_dma;
|
||||
|
||||
spi_dma.Parent = &spi;
|
||||
|
||||
HAL_SPI_Init(&spi);
|
||||
|
||||
set_initialized(false);
|
||||
|
||||
tail = 0;
|
||||
}
|
||||
|
||||
void ble_comm_start(void) {
|
||||
memset(spi_queue, 0, sizeof(spi_queue));
|
||||
head = 0, tail = 0;
|
||||
overrun = false;
|
||||
svc_enableIRQ(DMA2_Stream0_IRQn);
|
||||
HAL_SPI_Receive_DMA(&spi, spi_queue[0].buffer, BLE_PACKET_SIZE);
|
||||
spi_queue[0].used = true;
|
||||
g_comm_running = true;
|
||||
ble_signal_running();
|
||||
}
|
||||
|
||||
void ble_comm_stop(void) {
|
||||
ble_signal_off();
|
||||
g_comm_running = false;
|
||||
svc_disableIRQ(DMA2_Stream0_IRQn);
|
||||
HAL_SPI_Abort(&spi);
|
||||
memset(spi_queue, 0, sizeof(spi_queue));
|
||||
}
|
||||
|
||||
bool ble_comm_running(void) { return g_comm_running; }
|
||||
|
||||
void ble_comm_send(uint8_t *data, uint32_t len) {
|
||||
HAL_UART_Transmit(&urt, data, len, 30);
|
||||
}
|
||||
|
||||
uint32_t ble_comm_receive(uint8_t *data, uint32_t len) {
|
||||
if (urt.Instance->SR & USART_SR_RXNE) {
|
||||
HAL_StatusTypeDef result = HAL_UART_Receive(&urt, data, len, 30);
|
||||
|
||||
if (result == HAL_OK) {
|
||||
return len;
|
||||
} else {
|
||||
if (urt.RxXferCount == len) {
|
||||
return 0;
|
||||
}
|
||||
return len - urt.RxXferCount - 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ble_int_comm_send(uint8_t *data, uint32_t len, uint8_t message_type) {
|
||||
uint16_t msg_len = len + OVERHEAD_SIZE;
|
||||
uint8_t len_hi = msg_len >> 8;
|
||||
uint8_t len_lo = msg_len & 0xFF;
|
||||
uint8_t eom = EOM;
|
||||
|
||||
HAL_UART_Transmit(&urt, &message_type, 1, 1);
|
||||
HAL_UART_Transmit(&urt, &len_hi, 1, 1);
|
||||
HAL_UART_Transmit(&urt, &len_lo, 1, 1);
|
||||
|
||||
HAL_UART_Transmit(&urt, data, len, 10);
|
||||
HAL_UART_Transmit(&urt, &eom, 1, 1);
|
||||
}
|
||||
|
||||
void flush_line(void) {
|
||||
while (urt.Instance->SR & USART_SR_RXNE) {
|
||||
(void)urt.Instance->DR;
|
||||
}
|
||||
}
|
||||
|
||||
void ble_uart_receive(void) {
|
||||
if (urt.Instance->SR & USART_SR_RXNE) {
|
||||
uint8_t init_byte = 0;
|
||||
|
||||
HAL_UART_Receive(&urt, &init_byte, 1, 1);
|
||||
|
||||
if (init_byte == INTERNAL_EVENT || init_byte == INTERNAL_MESSAGE) {
|
||||
uint8_t len_hi = 0;
|
||||
uint8_t len_lo = 0;
|
||||
HAL_UART_Receive(&urt, &len_hi, 1, 1);
|
||||
HAL_UART_Receive(&urt, &len_lo, 1, 1);
|
||||
|
||||
uint16_t act_len = (len_hi << 8) | len_lo;
|
||||
|
||||
if (act_len > UART_PACKET_SIZE) {
|
||||
flush_line();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *data = NULL;
|
||||
uint16_t *len = NULL;
|
||||
if (init_byte == INTERNAL_EVENT) {
|
||||
data = int_event_buffer;
|
||||
len = &int_event_msg_len;
|
||||
} else if (init_byte == INTERNAL_MESSAGE) {
|
||||
data = int_comm_buffer;
|
||||
len = &int_comm_msg_len;
|
||||
} else {
|
||||
memset(data, 0, USB_DATA_SIZE);
|
||||
*len = 0;
|
||||
flush_line();
|
||||
return;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef result =
|
||||
HAL_UART_Receive(&urt, data, act_len - OVERHEAD_SIZE, 5);
|
||||
|
||||
if (result != HAL_OK) {
|
||||
memset(data, 0, USB_DATA_SIZE);
|
||||
*len = 0;
|
||||
flush_line();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t eom = 0;
|
||||
HAL_UART_Receive(&urt, &eom, 1, 1);
|
||||
|
||||
if (eom == EOM) {
|
||||
*len = act_len - OVERHEAD_SIZE;
|
||||
} else {
|
||||
memset(data, 0, USB_DATA_SIZE);
|
||||
*len = 0;
|
||||
flush_line();
|
||||
}
|
||||
} else {
|
||||
flush_line();
|
||||
}
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
void ble_event_poll() {
|
||||
ble_uart_receive();
|
||||
|
||||
if (int_event_msg_len > 0) {
|
||||
process_poll(int_event_buffer, int_event_msg_len);
|
||||
memset(int_event_buffer, 0, USB_DATA_SIZE);
|
||||
int_event_msg_len = 0;
|
||||
}
|
||||
|
||||
if (!ble_initialized() && !is_ble_dfu_mode() && ble_firmware_running()) {
|
||||
send_state_request();
|
||||
}
|
||||
}
|
||||
|
||||
bool ble_firmware_running(void) {
|
||||
return HAL_GPIO_ReadPin(GPIO_2_PORT, GPIO_2_PIN) != 0;
|
||||
}
|
||||
|
||||
uint32_t ble_int_event_receive(uint8_t *data, uint32_t len) {
|
||||
ble_uart_receive();
|
||||
if (int_event_msg_len > 0) {
|
||||
memcpy(data, int_event_buffer,
|
||||
int_event_msg_len > len ? len : int_event_msg_len);
|
||||
memset(int_event_buffer, 0, USB_DATA_SIZE);
|
||||
uint32_t res = int_event_msg_len;
|
||||
int_event_msg_len = 0;
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t ble_int_comm_receive(uint8_t *data, uint32_t len) {
|
||||
ble_uart_receive();
|
||||
if (int_comm_msg_len > 0) {
|
||||
memcpy(data, int_comm_buffer,
|
||||
int_comm_msg_len > len ? len : int_comm_msg_len);
|
||||
memset(int_comm_buffer, 0, USB_DATA_SIZE);
|
||||
uint32_t res = int_comm_msg_len;
|
||||
int_comm_msg_len = 0;
|
||||
uint8_t cmd = INTERNAL_CMD_ACK;
|
||||
ble_int_comm_send(&cmd, sizeof(cmd), INTERNAL_EVENT);
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool start_spi_dma(void) {
|
||||
int tmp_tail = (tail + 1) % SPI_QUEUE_SIZE;
|
||||
if (spi_queue[tmp_tail].used || spi_queue[tmp_tail].ready) {
|
||||
overrun = true;
|
||||
overrun_count++;
|
||||
if (first_overrun_at == 0) {
|
||||
first_overrun_at = msg_cntr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
spi_queue[tmp_tail].used = true;
|
||||
HAL_SPI_Receive_DMA(&spi, spi_queue[tmp_tail].buffer, BLE_PACKET_SIZE);
|
||||
|
||||
tail = tmp_tail;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DMA2_Stream0_IRQHandler(void) {
|
||||
IRQ_ENTER(DMA2_Stream0_IRQn);
|
||||
|
||||
HAL_DMA_IRQHandler(&spi_dma);
|
||||
|
||||
IRQ_EXIT(DMA2_Stream0_IRQn);
|
||||
}
|
||||
|
||||
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
spi_queue[tail].ready = true;
|
||||
msg_cntr++;
|
||||
start_spi_dma();
|
||||
}
|
||||
|
||||
uint32_t ble_ext_comm_receive(uint8_t *data, uint32_t len) {
|
||||
svc_disableIRQ(DMA2_Stream0_IRQn);
|
||||
if (spi_queue[head].ready) {
|
||||
uint8_t *buffer = (uint8_t *)spi_queue[head].buffer;
|
||||
memcpy(data, buffer, len > BLE_PACKET_SIZE ? BLE_PACKET_SIZE : len);
|
||||
|
||||
spi_queue[head].used = false;
|
||||
spi_queue[head].ready = false;
|
||||
head = (head + 1) % SPI_QUEUE_SIZE;
|
||||
|
||||
if (overrun && start_spi_dma()) {
|
||||
// overrun was before, need to restart the DMA
|
||||
overrun = false;
|
||||
}
|
||||
|
||||
if (data[0] != '?') {
|
||||
// bad packet, restart the DMA
|
||||
HAL_SPI_Abort(&spi);
|
||||
|
||||
memset(spi_queue, 0, sizeof(spi_queue));
|
||||
head = 0;
|
||||
tail = 0;
|
||||
overrun = false;
|
||||
HAL_SPI_Receive_DMA(&spi, spi_queue[0].buffer, BLE_PACKET_SIZE);
|
||||
spi_queue[0].used = true;
|
||||
// todo return error?
|
||||
svc_enableIRQ(DMA2_Stream0_IRQn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
svc_enableIRQ(DMA2_Stream0_IRQn);
|
||||
return len > BLE_PACKET_SIZE ? BLE_PACKET_SIZE : len;
|
||||
}
|
||||
|
||||
svc_enableIRQ(DMA2_Stream0_IRQn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ble_reset_to_bootloader(void) {
|
||||
uint32_t tick_start = 0;
|
||||
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
|
||||
|
||||
HAL_Delay(10);
|
||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
|
||||
|
||||
tick_start = HAL_GetTick();
|
||||
|
||||
while (HAL_GPIO_ReadPin(GPIO_1_PORT, GPIO_1_PIN) == GPIO_PIN_RESET) {
|
||||
if (HAL_GetTick() - tick_start > 4000) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
|
||||
|
||||
HAL_Delay(1000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ble_reset(void) {
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
|
||||
HAL_Delay(50);
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ble_signal_running(void) {
|
||||
HAL_GPIO_WritePin(GPIO_3_PORT, GPIO_3_PIN, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
void ble_signal_off(void) {
|
||||
HAL_GPIO_WritePin(GPIO_3_PORT, GPIO_3_PIN, GPIO_PIN_RESET);
|
||||
}
|
@ -5,6 +5,10 @@
|
||||
#include "../mpu.h"
|
||||
#include "common.h"
|
||||
#include "supervise.h"
|
||||
#include TREZOR_BOARD
|
||||
#ifdef USE_BLE
|
||||
#include "ble/ble.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARM_USER_MODE
|
||||
|
||||
@ -72,6 +76,10 @@ void SVC_C_Handler(uint32_t *stack) {
|
||||
;
|
||||
break;
|
||||
case SVC_REBOOT_TO_BOOTLOADER:
|
||||
#ifdef USE_BLE
|
||||
ble_stop_all_comm();
|
||||
// TODO: make sure that no answer is pending from NRF
|
||||
#endif
|
||||
ensure_compatible_settings();
|
||||
|
||||
__asm__ volatile("msr control, %0" ::"r"(0x0));
|
||||
|
@ -187,6 +187,14 @@ secbool usb_configured(void) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
secbool usb_configured_now(void) {
|
||||
const USBD_HandleTypeDef *pdev = &usb_dev_handle;
|
||||
if (pdev->dev_state == USBD_STATE_CONFIGURED) {
|
||||
return sectrue;
|
||||
}
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility functions for USB interfaces
|
||||
*/
|
||||
|
19
core/embed/trezorhal/unix/ble.h
Normal file
19
core/embed/trezorhal/unix/ble.h
Normal file
@ -0,0 +1,19 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void ble_comm_init(void);
|
||||
|
||||
void ble_comm_send(uint8_t *data, uint32_t len);
|
||||
uint32_t ble_comm_receive(uint8_t *data, uint32_t len);
|
||||
|
||||
void ble_int_comm_send(uint8_t *data, uint32_t len, uint8_t message_type);
|
||||
uint32_t ble_int_event_receive(uint8_t *data, uint32_t len);
|
||||
uint32_t ble_int_comm_receive(uint8_t *data, uint32_t len);
|
||||
uint32_t ble_ext_comm_receive(uint8_t *data, uint32_t len);
|
||||
|
||||
void ble_event_poll(void);
|
||||
|
||||
bool ble_firmware_running(void);
|
||||
|
||||
bool ble_reset_to_bootloader(void);
|
||||
bool ble_reset(void);
|
@ -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
|
||||
|
@ -115,6 +115,7 @@ VERSION_PATCH: int
|
||||
USE_BLE: bool
|
||||
USE_SD_CARD: bool
|
||||
"""Whether the hardware supports SD card."""
|
||||
USE_BACKLIGHT: bool
|
||||
USE_TOUCH: bool
|
||||
USE_BUTTON: bool
|
||||
USE_BACKLIGHT: bool
|
||||
|
@ -31,6 +31,7 @@ def stm32f4_common_files(env, defines, sources, paths):
|
||||
"vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_sdram.c",
|
||||
"vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c",
|
||||
"vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c",
|
||||
"vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c",
|
||||
"vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_fmc.c",
|
||||
"vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.c",
|
||||
]
|
||||
|
@ -4,8 +4,6 @@ import subprocess
|
||||
import zlib
|
||||
from pathlib import Path
|
||||
|
||||
import subprocess
|
||||
|
||||
from boards import (
|
||||
discovery,
|
||||
trezor_1,
|
||||
@ -105,14 +103,14 @@ def get_version_int(file):
|
||||
patch = 0
|
||||
|
||||
file = PROJECT_ROOT / file
|
||||
with open(file, 'r') as f:
|
||||
with open(file, "r") as f:
|
||||
for line in f:
|
||||
if line.startswith('#define VERSION_MAJOR '):
|
||||
major = int(line.split('VERSION_MAJOR')[1].strip())
|
||||
if line.startswith('#define VERSION_MINOR '):
|
||||
minor = int(line.split('VERSION_MINOR')[1].strip())
|
||||
if line.startswith('#define VERSION_PATCH '):
|
||||
patch = int(line.split('VERSION_PATCH')[1].strip())
|
||||
if line.startswith("#define VERSION_MAJOR "):
|
||||
major = int(line.split("VERSION_MAJOR")[1].strip())
|
||||
if line.startswith("#define VERSION_MINOR "):
|
||||
minor = int(line.split("VERSION_MINOR")[1].strip())
|
||||
if line.startswith("#define VERSION_PATCH "):
|
||||
patch = int(line.split("VERSION_PATCH")[1].strip())
|
||||
if major > 99 or minor > 99 or patch > 99:
|
||||
raise Exception("Version number too large")
|
||||
return major * 10000 + minor * 100 + patch
|
||||
|
@ -9,7 +9,7 @@ if __debug__:
|
||||
import trezorui2
|
||||
from storage import debug as storage
|
||||
from storage.debug import debug_events
|
||||
from trezor import log, loop, utils, wire
|
||||
from trezor import log, loop, wire
|
||||
from trezor.enums import MessageType
|
||||
from trezor.messages import DebugLinkLayout, Success
|
||||
from trezor.ui import display
|
||||
|
@ -16,4 +16,5 @@ NotInitialized = 11
|
||||
PinMismatch = 12
|
||||
WipeCodeMismatch = 13
|
||||
InvalidSession = 14
|
||||
DeviceIsBusy = 15
|
||||
FirmwareError = 99
|
||||
|
@ -286,6 +286,7 @@ if TYPE_CHECKING:
|
||||
PinMismatch = 12
|
||||
WipeCodeMismatch = 13
|
||||
InvalidSession = 14
|
||||
DeviceIsBusy = 15
|
||||
FirmwareError = 99
|
||||
|
||||
class ButtonRequestType(IntEnum):
|
||||
|
@ -10,8 +10,8 @@ from trezorutils import ( # noqa: F401
|
||||
UI_LAYOUT,
|
||||
USE_BACKLIGHT,
|
||||
USE_BLE,
|
||||
USE_OPTIGA,
|
||||
USE_BUTTON,
|
||||
USE_OPTIGA,
|
||||
USE_SD_CARD,
|
||||
USE_TOUCH,
|
||||
VERSION_MAJOR,
|
||||
|
Loading…
Reference in New Issue
Block a user