mmilata/ble-rebased
tychovrahe 12 months ago committed by Martin Milata
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,105 +246,166 @@ 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;
comm_result_t res = process_common_messages(USB_IFACE_NUM, buf, vhdr, hdr);
if (res != NO_RESULT) {
return res;
}
switch (msg_id) {
case MessageType_MessageType_Initialize:
process_msg_Initialize(USB_IFACE_NUM, msg_size, buf, vhdr, hdr);
}
}
#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;
case MessageType_MessageType_Ping:
process_msg_Ping(USB_IFACE_NUM, msg_size, buf);
}
r = ble_int_comm_receive(buf, sizeof(buf));
if (r != 0) {
active_iface = BLE_INT_IFACE_NUM;
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;
}
}
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;
}
}
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;
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;
}
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();
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;
}
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;
r = 0;
comm_result_t res =
process_common_messages(active_iface, buf, vhdr, hdr);
if (res != NO_RESULT) {
return res;
}
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;
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) {
@ -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);
}
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;
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);
}
const uint32_t msg_size = sizestream.bytes_written;
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,
},
};
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;
#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
}
#define BLE_GAP_PASSKEY_LEN 6
_usb_write_flush(&state);
/* 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;
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)
typedef struct {
uint8_t iface_num;
uint8_t packet_index;
uint8_t packet_pos;
uint8_t *buf;
} usb_read_state;
static bool _read_authkey(pb_istream_t *stream, const pb_field_t *field,
void **arg) {
uint8_t *key_buffer = (uint8_t *)(*arg);
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 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)
static void _read_flush(read_state *state) { (void)state; }
#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();

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

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

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

@ -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 *************************************************/

@ -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 *************************************************/

@ -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 *************************************************/

@ -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 *************************************************/

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

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

@ -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
*/

@ -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…
Cancel
Save