fix(core): improve homescreen upload speed over BLE
What changed, and why it matters
This commit adds a new Bluetooth Low Energy (BLE) 'high speed' mode that is temporarily enabled only while uploading a custom homescreen image, then turned off afterward. It is a performance optimization, not a security fix. There is no evidence in the commit of a vulnerability, attack, or security-relevant bug.
No security action required. Treat as a normal feature/performance commit. If reviewing further, verify that the underlying C/NRF implementation of `ble_set_high_speed` does not weaken pairing or encryption parameters.
Security signals we found
No memory-safety changes
No input validation changes
No cryptographic or authentication changes
No privilege-boundary changes
No changelog entry; commit describes performance improvement only
Evidence from the diff
The patch exposes a new ble_set_high_speed() syscall and a matching MicroPython binding trezorble.set_high_speed(enable). During ApplySettings with homescreen_length, the firmware now calls set_high_speed(True) before _load_homescreen() and set_high_speed(False) in a finally block. The change is gated by utils.USE_BLE. No input validation, buffer handling, or cryptographic logic is modified.
Changed components
core/embed/rust/src/trezorhal/blecore/embed/sys/syscall/stm32/syscall_dispatch.ccore/embed/sys/syscall/stm32/syscall_stubs.ccore/src/apps/management/apply_settings.pyInspect captured patch +49 / −1
diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs
index 204e52a00..6780045b9 100644
--- a/core/embed/rust/build.rs
+++ b/core/embed/rust/build.rs
@@ -430,6 +430,7 @@ fn generate_trezorhal_bindings() {
.allowlist_function("ble_set_name")
.allowlist_function("ble_unpair")
.allowlist_function("ble_get_bond_list")
+ .allowlist_function("ble_set_high_speed")
.allowlist_type("ble_command_t")
.allowlist_type("ble_state_t")
.allowlist_type("ble_event_t")
diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h
index 540f67599..7731966dc 100644
--- a/core/embed/rust/librust_qstr.h
+++ b/core/embed/rust/librust_qstr.h
@@ -792,6 +792,7 @@ static void _librust_qstrs(void) {
MP_QSTR_send__transaction_signed;
MP_QSTR_send__you_are_contributing;
MP_QSTR_set_brightness;
+ MP_QSTR_set_high_speed;
MP_QSTR_set_name;
MP_QSTR_setting__adjust;
MP_QSTR_setting__apply;
diff --git a/core/embed/rust/src/trezorhal/ble/micropython.rs b/core/embed/rust/src/trezorhal/ble/micropython.rs
index 693a7f989..452beff35 100644
--- a/core/embed/rust/src/trezorhal/ble/micropython.rs
+++ b/core/embed/rust/src/trezorhal/ble/micropython.rs
@@ -87,6 +87,17 @@ extern "C" fn py_set_name(name: Obj) -> Obj {
unsafe { util::try_or_raise(block) }
}
+extern "C" fn py_set_high_speed(enable: Obj) -> Obj {
+ let block = || {
+ let enable: bool = enable.try_into()?;
+
+ set_high_speed(enable);
+
+ Ok(Obj::const_none())
+ };
+ unsafe { util::try_or_raise(block) }
+}
+
extern "C" fn py_switch_off() -> Obj {
let block = || {
switch_off()?;
@@ -323,6 +334,12 @@ pub static mp_module_trezorble: Module = obj_module! {
/// """
Qstr::MP_QSTR_set_name => obj_fn_1!(py_set_name).as_obj(),
+ /// def set_high_speed(enable: bool):
+ /// """
+ /// Set high speed connection.
+ /// """
+ Qstr::MP_QSTR_set_high_speed => obj_fn_1!(py_set_high_speed).as_obj(),
+
/// def switch_off():
/// """
/// Stop advertising and disconnect any connected devices.
diff --git a/core/embed/rust/src/trezorhal/ble/mod.rs b/core/embed/rust/src/trezorhal/ble/mod.rs
index 6fd39c476..5ad1f5f6b 100644
--- a/core/embed/rust/src/trezorhal/ble/mod.rs
+++ b/core/embed/rust/src/trezorhal/ble/mod.rs
@@ -170,6 +170,10 @@ pub fn set_name(name: &str) {
unsafe { ffi::ble_set_name(bytes.as_ptr(), bytes.len()) }
}
+pub fn set_high_speed(enable: bool) {
+ unsafe { ffi::ble_set_high_speed(enable) }
+}
+
pub fn start_comm() {
unsafe { ffi::ble_start() }
}
diff --git a/core/embed/sys/syscall/inc/sys/syscall_numbers.h b/core/embed/sys/syscall/inc/sys/syscall_numbers.h
index 49c9003d6..7a483d190 100644
--- a/core/embed/sys/syscall/inc/sys/syscall_numbers.h
+++ b/core/embed/sys/syscall/inc/sys/syscall_numbers.h
@@ -129,6 +129,7 @@ typedef enum {
SYSCALL_BLE_SET_NAME,
SYSCALL_BLE_UNPAIR,
SYSCALL_BLE_GET_BOND_LIST,
+ SYSCALL_BLE_SET_HIGH_SPEED,
SYSCALL_NRF_UPDATE_REQUIRED,
SYSCALL_NRF_UPDATE,
diff --git a/core/embed/sys/syscall/stm32/syscall_dispatch.c b/core/embed/sys/syscall/stm32/syscall_dispatch.c
index 785544807..34949c005 100644
--- a/core/embed/sys/syscall/stm32/syscall_dispatch.c
+++ b/core/embed/sys/syscall/stm32/syscall_dispatch.c
@@ -639,6 +639,11 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
size_t list_size = args[1];
args[0] = ble_get_bond_list__verified(list, list_size);
} break;
+
+ case SYSCALL_BLE_SET_HIGH_SPEED: {
+ bool enable = args[0];
+ ble_set_high_speed(enable);
+ } break;
#endif
#ifdef USE_NRF
diff --git a/core/embed/sys/syscall/stm32/syscall_stubs.c b/core/embed/sys/syscall/stm32/syscall_stubs.c
index f8c4ff53d..1a463ca0f 100644
--- a/core/embed/sys/syscall/stm32/syscall_stubs.c
+++ b/core/embed/sys/syscall/stm32/syscall_stubs.c
@@ -621,6 +621,10 @@ uint8_t ble_get_bond_list(bt_le_addr_t *bonds, size_t count) {
SYSCALL_BLE_GET_BOND_LIST);
}
+void ble_set_high_speed(bool enable) {
+ syscall_invoke1((uint32_t)enable, SYSCALL_BLE_SET_HIGH_SPEED);
+}
+
#endif
#ifdef USE_NRF
diff --git a/core/mocks/generated/trezorble.pyi b/core/mocks/generated/trezorble.pyi
index 6cb86d4f0..a68608e8e 100644
--- a/core/mocks/generated/trezorble.pyi
+++ b/core/mocks/generated/trezorble.pyi
@@ -68,6 +68,13 @@ def set_name(name: str | None):
"""
+# rust/src/trezorhal/ble/micropython.rs
+def set_high_speed(enable: bool):
+ """
+ Set high speed connection.
+ """
+
+
# rust/src/trezorhal/ble/micropython.rs
def switch_off():
"""
diff --git a/core/src/apps/management/apply_settings.py b/core/src/apps/management/apply_settings.py
index 17712f194..b90ba49ac 100644
--- a/core/src/apps/management/apply_settings.py
+++ b/core/src/apps/management/apply_settings.py
@@ -92,8 +92,16 @@ async def apply_settings(msg: ApplySettings) -> Success:
if homescreen_length is not None:
if homescreen is not None:
raise ProcessError("Mutually exclusive settings")
+ if utils.USE_BLE:
+ from trezorble import set_high_speed
- homescreen = await _load_homescreen(homescreen_length)
+ set_high_speed(True)
+
+ try:
+ homescreen = await _load_homescreen(homescreen_length)
+ finally:
+ if utils.USE_BLE:
+ set_high_speed(False)
if homescreen is not None:
_validate_homescreen(homescreen)
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.