refactor(core/bootloader): unify bootloader event loop in rust
What changed, and why it matters
This commit is a large internal refactor of the Trezor bootloader's event loop, moving it from C into Rust and changing how screens handle USB/Bluetooth communication. The title and message explicitly call it a refactor with '[no changelog]', and there is no vendor statement that this fixes a security bug. The diff shows substantial code movement but no obvious new vulnerability. Because it is a wide-reaching rewrite of security-critical boot-time code, it carries ordinary implementation risk, but the available materials do not demonstrate a concrete security issue.
Treat as a normal high-risk refactor: run full bootloader test suite, verify USB/BLE message dispatch, confirm power-manager suspend/hibernate behavior, and check that workflow_result_t constant changes do not break ABI with remaining C callers. No immediate security patch is indicated by the supplied materials.
Security signals we found
Large refactor of bootloader event loop (security-critical code)
Removal of C workflow_host_control() and migration of USB/BLE dispatch to Rust
Change of workflow_result_t magic constants (ABI risk, not exploit)
Power-manager idle/suspend/hibernate logic moved into Rust loop
No vendor security claim or changelog entry present
Evidence from the diff
The patch unifies the bootloader event loop in Rust. It removes the C workflow_host_control() loop and replaces per-screen C layout objects with Rust Component-based screens that call a new bootloader::run() loop. The new loop polls sysevents, dispatches USB/BLE messages to bootloader_process_usb()/bootloader_process_ble(), and handles power-manager fade/suspend/hibernate logic. Several workflow_result_t magic constants were changed (e.g., WF_OK_UI_ACTION 0xAABBCCEE -> 0x5ABBCCEE). The C side now exposes usb_iface_get()/ble_iface_get() and smaller protob handlers. No explicit security fix or CVE is mentioned.
Changed components
Trezor firmware bootloadercore/embed/projects/bootloader/workflowcore/embed/projects/bootloader/wirecore/embed/rust/src/bootloadercore/embed/rust/src/ui/api/bootloader_c.rscore/embed/rust/src/ui/ui_bootloader.rscore/embed/rust/src/trezorhal/sysevent.rsInspect captured patch +633 / −817
diff --git a/core/embed/projects/bootloader/wire/wire_iface_ble.c b/core/embed/projects/bootloader/wire/wire_iface_ble.c
index 3b41b9cd..74f9be28 100644
--- a/core/embed/projects/bootloader/wire/wire_iface_ble.c
+++ b/core/embed/projects/bootloader/wire/wire_iface_ble.c
@@ -206,4 +206,11 @@ bool ble_iface_start_pairing(void) {
return true;
}
+wire_iface_t* ble_iface_get(void) {
+ if (!g_ble_iface.initialized) {
+ return NULL;
+ }
+ return &g_ble_iface;
+}
+
#endif
diff --git a/core/embed/projects/bootloader/wire/wire_iface_ble.h b/core/embed/projects/bootloader/wire/wire_iface_ble.h
index 7e1855fd..4ba36971 100644
--- a/core/embed/projects/bootloader/wire/wire_iface_ble.h
+++ b/core/embed/projects/bootloader/wire/wire_iface_ble.h
@@ -28,3 +28,5 @@ void ble_iface_deinit(void);
bool ble_iface_start_pairing(void);
void ble_iface_end_pairing(void);
+
+wire_iface_t* ble_iface_get(void);
diff --git a/core/embed/projects/bootloader/wire/wire_iface_usb.c b/core/embed/projects/bootloader/wire/wire_iface_usb.c
index aad70964..106a128c 100644
--- a/core/embed/projects/bootloader/wire/wire_iface_usb.c
+++ b/core/embed/projects/bootloader/wire/wire_iface_usb.c
@@ -97,3 +97,10 @@ void usb_iface_deinit(void) {
memset(iface, 0, sizeof(wire_iface_t));
usb_stop();
}
+
+wire_iface_t* usb_iface_get(void) {
+ if (!g_usb_iface.initialized) {
+ return NULL;
+ }
+ return &g_usb_iface;
+}
diff --git a/core/embed/projects/bootloader/wire/wire_iface_usb.h b/core/embed/projects/bootloader/wire/wire_iface_usb.h
index 9facf01a..c1b9035e 100644
--- a/core/embed/projects/bootloader/wire/wire_iface_usb.h
+++ b/core/embed/projects/bootloader/wire/wire_iface_usb.h
@@ -24,4 +24,6 @@
wire_iface_t *usb_iface_init(secbool usb21_landing);
+wire_iface_t *usb_iface_get(void);
+
void usb_iface_deinit(void);
diff --git a/core/embed/projects/bootloader/workflow/wf_auto_update.c b/core/embed/projects/bootloader/workflow/wf_auto_update.c
index 247b65f0..bb1ca2b9 100644
--- a/core/embed/projects/bootloader/workflow/wf_auto_update.c
+++ b/core/embed/projects/bootloader/workflow/wf_auto_update.c
@@ -32,7 +32,6 @@
workflow_result_t workflow_auto_update(const fw_info_t *fw) {
ui_set_initial_setup(true);
- workflow_result_t res = WF_CANCELLED;
uint32_t ui_result = CONNECT_CANCEL;
protob_ios_t ios;
@@ -40,10 +39,7 @@ workflow_result_t workflow_auto_update(const fw_info_t *fw) {
workflow_ifaces_init(secfalse, &ios);
notify_send(NOTIFY_UNLOCK);
- c_layout_t layout;
- memset(&layout, 0, sizeof(layout));
- screen_connect(true, false, &layout);
- res = workflow_host_control(fw, &layout, &ui_result, &ios);
+ workflow_result_t res = screen_connect(true, false, &ui_result);
if (res == WF_OK_UI_ACTION && ui_result == CONNECT_CANCEL) {
bootargs_set(BOOT_COMMAND_NONE, NULL, 0);
diff --git a/core/embed/projects/bootloader/workflow/wf_ble_pairing_request.c b/core/embed/projects/bootloader/workflow/wf_ble_pairing_request.c
index 7c44663e..9a76e074 100644
--- a/core/embed/projects/bootloader/workflow/wf_ble_pairing_request.c
+++ b/core/embed/projects/bootloader/workflow/wf_ble_pairing_request.c
@@ -58,12 +58,9 @@ workflow_result_t workflow_ble_pairing_request(const fw_info_t *fw) {
rgb_led_effect_start(RGB_LED_EFFECT_PAIRING, 0);
#endif
- c_layout_t layout;
- memset(&layout, 0, sizeof(layout));
- screen_pairing_mode(ui_get_initial_setup(), name, strlen(name), &layout);
-
uint32_t code = 0;
- workflow_result_t res = workflow_host_control(fw, &layout, &code, NULL);
+ workflow_result_t res =
+ screen_pairing_mode(ui_get_initial_setup(), name, strlen(name), &code);
#ifdef USE_RGB_LED
rgb_led_effect_stop();
@@ -140,12 +137,8 @@ workflow_result_t workflow_wireless_setup(const fw_info_t *fw,
rgb_led_effect_start(RGB_LED_EFFECT_PAIRING, 0);
#endif
- c_layout_t layout;
- memset(&layout, 0, sizeof(layout));
- screen_wireless_setup(name, strlen(name), &layout);
-
uint32_t code = 0;
- workflow_result_t res = workflow_host_control(fw, &layout, &code, ios);
+ workflow_result_t res = screen_wireless_setup(name, strlen(name), &code);
#ifdef USE_RGB_LED
rgb_led_effect_stop();
diff --git a/core/embed/projects/bootloader/workflow/wf_bootloader.c b/core/embed/projects/bootloader/workflow/wf_bootloader.c
index eb3744e8..043475ee 100644
--- a/core/embed/projects/bootloader/workflow/wf_bootloader.c
+++ b/core/embed/projects/bootloader/workflow/wf_bootloader.c
@@ -41,12 +41,9 @@
workflow_result_t workflow_menu(const fw_info_t* fw, protob_ios_t* ios) {
while (true) {
- c_layout_t layout;
- memset(&layout, 0, sizeof(layout));
- screen_menu(ui_get_initial_setup(), &layout);
uint32_t ui_result = 0;
workflow_result_t result =
- workflow_host_control(fw, &layout, &ui_result, ios);
+ screen_menu(ui_get_initial_setup(), ios != NULL, &ui_result);
if (result != WF_OK_UI_ACTION) {
return result;
@@ -129,8 +126,6 @@ static screen_t handle_menu(const fw_info_t* fw,
static screen_t handle_wait_for_host(const fw_info_t* fw,
workflow_result_t* out_result) {
- c_layout_t layout;
- memset(&layout, 0, sizeof(layout));
uint32_t ui_res = 0;
protob_ios_t ios;
@@ -141,8 +136,7 @@ static screen_t handle_wait_for_host(const fw_info_t* fw,
screen_t next_screen = SCREEN_WAIT_FOR_HOST;
while (next_screen == SCREEN_WAIT_FOR_HOST) {
- screen_connect(false, true, &layout);
- workflow_result_t res = workflow_host_control(fw, &layout, &ui_res, &ios);
+ workflow_result_t res = screen_connect(false, true, &ui_res);
switch (res) {
case WF_OK_UI_ACTION: {
diff --git a/core/embed/projects/bootloader/workflow/wf_empty_device.c b/core/embed/projects/bootloader/workflow/wf_empty_device.c
index f5d8cf78..474134be 100644
--- a/core/embed/projects/bootloader/workflow/wf_empty_device.c
+++ b/core/embed/projects/bootloader/workflow/wf_empty_device.c
@@ -68,10 +68,7 @@ workflow_result_t workflow_empty_device(void) {
uint32_t ui_result = WELCOME_CANCEL;
while (res == WF_CANCELLED ||
(res == WF_OK_UI_ACTION && ui_result == WELCOME_CANCEL)) {
- c_layout_t layout;
- memset(&layout, 0, sizeof(layout));
- screen_welcome(&layout);
- res = workflow_host_control(NULL, &layout, &ui_result, &ios);
+ res = screen_welcome(&ui_result);
#ifdef USE_BLE
if (res == WF_OK_UI_ACTION && ui_result == WELCOME_PAIRING_MODE) {
res = workflow_wireless_setup(NULL, &ios);
diff --git a/core/embed/projects/bootloader/workflow/wf_host_control.c b/core/embed/projects/bootloader/workflow/wf_host_control.c
index 38553815..4e95db4e 100644
--- a/core/embed/projects/bootloader/workflow/wf_host_control.c
+++ b/core/embed/projects/bootloader/workflow/wf_host_control.c
@@ -22,7 +22,6 @@
#include <trezor_model.h>
#include <trezor_rtl.h>
-#include <sys/sysevent.h>
#include <sys/systick.h>
#include <sys/types.h>
#include <util/image.h>
@@ -31,237 +30,75 @@
#include "wire/wire_iface_usb.h"
#include "workflow.h"
-#ifdef USE_HAPTIC
-#include <io/haptic.h>
-#endif
-
#ifdef USE_BLE
#include <wire/wire_iface_ble.h>
#endif
-#ifdef USE_BUTTON
-#include <io/button.h>
-#endif
-
-#ifdef USE_POWER_MANAGER
-#include <io/display.h>
-#include <io/display_utils.h>
-#include <sys/power_manager.h>
-
-#define FADE_TIME_MS 30000
-#define SUSPEND_TIME_MS 40000
-
-#endif
-
-workflow_result_t workflow_host_control(const fw_info_t *fw,
- c_layout_t *wait_layout,
- uint32_t *ui_action_result,
- protob_ios_t *ios) {
- workflow_result_t result = WF_ERROR_FATAL;
-
-#ifdef USE_POWER_MANAGER
- uint32_t button_deadline = 0;
-#ifdef USE_HAPTIC
- bool button_haptic_played = false;
-#endif
- uint32_t fade_deadline = ticks_timeout(FADE_TIME_MS);
- uint32_t suspend_deadline = ticks_timeout(SUSPEND_TIME_MS);
- bool faded = false;
- int fade_value = display_get_backlight();
-#endif
-
- sysevents_t awaited = {0};
-
- if (ios != NULL) {
- for (size_t i = 0; i < ios->count; i++) {
- awaited.read_ready |= 1 << protob_get_iface_flag(&ios->ifaces[i]);
- }
+static workflow_result_t bootloader_process_comm(wire_iface_t *wire_iface) {
+ if (wire_iface == NULL) {
+ // continue with the event processing
+ return WF_OK;
}
-#ifdef USE_BLE
- awaited.read_ready |= 1 << SYSHANDLE_BLE;
-#endif
-#ifdef USE_BUTTON
- awaited.read_ready |= 1 << SYSHANDLE_BUTTON;
-#endif
-#ifdef USE_TOUCH
- awaited.read_ready |= 1 << SYSHANDLE_TOUCH;
-#endif
-#ifdef USE_POWER_MANAGER
- awaited.read_ready |= 1 << SYSHANDLE_POWER_MANAGER;
-#endif
+ protob_io_t active_iface;
+ protob_init(&active_iface, wire_iface);
- uint32_t res = screen_attach(wait_layout);
-
- if (res != 0) {
- if (ui_action_result != NULL) {
- *ui_action_result = res;
- }
- result = WF_OK_UI_ACTION;
- goto exit_host_control;
+ uint16_t msg_id = 0;
+ if (sectrue != protob_get_msg_header(&active_iface, &msg_id)) {
+ return WF_OK;
}
- for (;;) {
- sysevents_t signalled = {0};
-
- sysevents_poll(&awaited, &signalled, ticks_timeout(100));
-
-#ifdef USE_POWER_MANAGER
-
-#ifdef USE_HAPTIC
- if (button_deadline != 0 && !button_haptic_played &&
- ticks_expired(button_deadline)) {
- // we reached hibernation time
- haptic_play(HAPTIC_BOOTLOADER_ENTRY);
- button_haptic_played = true;
- }
-#endif
-
- if (signalled.read_ready == 0) {
- pm_state_t pm_state = {0};
-
- pm_get_state(&pm_state);
-
- if (pm_state.usb_connected) {
- fade_deadline = ticks_timeout(FADE_TIME_MS);
- suspend_deadline = ticks_timeout(SUSPEND_TIME_MS);
- continue;
- }
-
- // device idle.
- if (!faded && ticks_expired(fade_deadline)) {
- fade_value = display_get_backlight();
- display_fade(fade_value, BACKLIGHT_LOW, 200);
- faded = true;
- }
-
- if (ticks_expired(suspend_deadline)) {
- pm_suspend(NULL);
- screen_render(wait_layout);
- display_fade(display_get_backlight(), fade_value, 200);
- button_deadline = 0;
- faded = false;
- fade_deadline = ticks_timeout(FADE_TIME_MS);
- suspend_deadline = ticks_timeout(SUSPEND_TIME_MS);
- }
- continue;
- }
-
- fade_deadline = ticks_timeout(FADE_TIME_MS);
- suspend_deadline = ticks_timeout(SUSPEND_TIME_MS);
- if (faded) {
- display_fade(display_get_backlight(), fade_value, 200);
- faded = false;
- }
-
- // in case of battery powered device, power button is handled by eventloop
- if (signalled.read_ready & (1 << SYSHANDLE_BUTTON)) {
- button_event_t btn_event = {0};
- // todo this eats all button events, not only power button, so it needs to
- // be handled differently for button-based battery powered devices.
- if (button_get_event(&btn_event) && btn_event.button == BTN_POWER) {
- if (btn_event.event_type == BTN_EVENT_DOWN) {
- button_deadline = ticks_timeout(3000);
-#ifdef USE_HAPTIC
- button_haptic_played = false;
-#endif
- } else if (btn_event.event_type == BTN_EVENT_UP &&
- button_deadline != 0) {
- display_fade(display_get_backlight(), 0, 200);
- if (ticks_expired(button_deadline)) {
- // power button pressed for 3 seconds, we hibernate
-
-#ifdef USE_HAPTIC
- if (!button_haptic_played) {
- haptic_play(HAPTIC_BOOTLOADER_ENTRY);
- button_haptic_played = true;
- }
-#endif
- pm_hibernate();
- } else {
- pm_suspend(NULL);
- button_deadline = 0;
- screen_render(wait_layout);
- display_fade(display_get_backlight(), BACKLIGHT_NORMAL, 200);
- faded = false;
- fade_deadline = ticks_timeout(FADE_TIME_MS);
- suspend_deadline = ticks_timeout(SUSPEND_TIME_MS);
- }
- }
- }
- }
-
-#else
- if (signalled.read_ready == 0) {
- continue;
- }
-#endif
-
- uint16_t msg_id = 0;
- protob_io_t *active_iface = NULL;
-
- if (ios != NULL) {
- for (size_t i = 0; i < ios->count; i++) {
- if (signalled.read_ready ==
- (1 << protob_get_iface_flag(&ios->ifaces[i])) &&
- sectrue == protob_get_msg_header(&ios->ifaces[i], &msg_id)) {
- active_iface = &ios->ifaces[i];
- break;
- }
- }
- }
-
- // no data, lets pass the event signal to UI
- if (active_iface == NULL) {
- uint32_t res = screen_event(wait_layout, &signalled);
-
- if (res != 0) {
- if (ui_action_result != NULL) {
- *ui_action_result = res;
- }
- result = WF_OK_UI_ACTION;
- goto exit_host_control;
- }
- continue;
- }
-
- switch (msg_id) {
- case MessageType_MessageType_Initialize:
- workflow_initialize(active_iface, fw);
- // whatever the result, we stay here and continue
- break;
- case MessageType_MessageType_Ping:
- workflow_ping(active_iface);
- // whatever the result, we stay here and continue
- break;
- case MessageType_MessageType_GetFeatures:
- workflow_get_features(active_iface, fw);
- // whatever the result, we stay here and continue
- break;
- case MessageType_MessageType_WipeDevice:
- result = workflow_wipe_device(active_iface);
- goto exit_host_control;
- break;
- case MessageType_MessageType_FirmwareErase:
- result = workflow_firmware_update(active_iface);
- goto exit_host_control;
- break;
+ fw_info_t fw;
+ memset(&fw, 0, sizeof(fw));
+
+ switch (msg_id) {
+ case MessageType_MessageType_Initialize:
+ fw_check(&fw);
+ workflow_initialize(&active_iface, &fw);
+ // continue with the event processing
+ return WF_OK;
+ break;
+ case MessageType_MessageType_Ping:
+ workflow_ping(&active_iface);
+ // continue with the event processing
+ return WF_OK;
+ break;
+ case MessageType_MessageType_GetFeatures:
+ fw_check(&fw);
+ workflow_get_features(&active_iface, &fw);
+ // continue with the event processing
+ return WF_OK;
+ break;
+ case MessageType_MessageType_WipeDevice:
+ return workflow_wipe_device(&active_iface);
+ break;
+ case MessageType_MessageType_FirmwareErase:
+ return workflow_firmware_update(&active_iface);
+ break;
#if defined LOCKABLE_BOOTLOADER
- case MessageType_MessageType_UnlockBootloader:
- result = workflow_unlock_bootloader(active_iface);
- goto exit_host_control;
- break;
-#endif
- default:
- recv_msg_unknown(active_iface);
- break;
- }
+ case MessageType_MessageType_UnlockBootloader:
+ return workflow_unlock_bootloader(&active_iface);
+ break;
+#endif
+ default:
+ recv_msg_unknown(&active_iface);
+ // continue with the event processing
+ return WF_OK;
}
+}
-exit_host_control:
- return result;
+workflow_result_t bootloader_process_usb(void) {
+ wire_iface_t *iface = usb_iface_get();
+ return bootloader_process_comm(iface);
}
+#ifdef USE_BLE
+workflow_result_t bootloader_process_ble(void) {
+ wire_iface_t *iface = ble_iface_get();
+ return bootloader_process_comm(iface);
+}
+#endif
+
void workflow_ifaces_init(secbool usb21_landing, protob_ios_t *ios) {
size_t cnt = 1;
memset(ios, 0, sizeof(*ios));
diff --git a/core/embed/projects/bootloader/workflow/workflow.h b/core/embed/projects/bootloader/workflow/workflow.h
index fb1ca3db..4f649bdf 100644
--- a/core/embed/projects/bootloader/workflow/workflow.h
+++ b/core/embed/projects/bootloader/workflow/workflow.h
@@ -21,25 +21,10 @@
#include <trezor_types.h>
-#include <sys/sysevent.h>
#include <util/image.h>
#include "protob/protob.h"
-#include "rust_ui_bootloader.h"
-
-typedef enum {
- WF_ERROR_FATAL = 0,
- WF_ERROR = 0x11223344,
- WF_OK = 0x7ABBCCDD,
- WF_OK_REBOOT_SELECTED = 0x68A4DABF,
- WF_OK_FIRMWARE_INSTALLED = 0x04D9D07F,
- WF_OK_DEVICE_WIPED = 0x30DC3841,
- WF_OK_BOOTLOADER_UNLOCKED = 0x23FCBD03,
- WF_OK_UI_ACTION = 0xAABBCCEE,
- WF_OK_PAIRING_COMPLETED = 0xAABBCCEF,
- WF_OK_PAIRING_FAILED = 0xAABBCCF0,
- WF_CANCELLED = 0x55667788,
-} workflow_result_t;
+#include "workflow_common.h"
workflow_result_t workflow_firmware_update(protob_io_t *iface);
@@ -62,11 +47,6 @@ workflow_result_t workflow_bootloader(const fw_info_t *fw);
workflow_result_t workflow_empty_device(void);
-workflow_result_t workflow_host_control(const fw_info_t *fw,
- c_layout_t *wait_layout,
- uint32_t *ui_action_result,
- protob_ios_t *ios);
-
workflow_result_t workflow_auto_update(const fw_info_t *fw);
#ifdef USE_BLE
diff --git a/core/embed/projects/bootloader/workflow/workflow_common.h b/core/embed/projects/bootloader/workflow/workflow_common.h
new file mode 100644
index 00000000..5449efd0
--- /dev/null
+++ b/core/embed/projects/bootloader/workflow/workflow_common.h
@@ -0,0 +1,38 @@
+/*
+ * 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/>.
+ */
+
+#pragma once
+
+typedef enum {
+ WF_ERROR_FATAL = 0,
+ WF_ERROR = 0x11223344,
+ WF_OK = 0x7ABBCCDD,
+ WF_OK_REBOOT_SELECTED = 0x68A4DABF,
+ WF_OK_FIRMWARE_INSTALLED = 0x04D9D07F,
+ WF_OK_DEVICE_WIPED = 0x30DC3841,
+ WF_OK_BOOTLOADER_UNLOCKED = 0x23FCBD03,
+ WF_OK_UI_ACTION = 0x5ABBCCEE,
+ WF_OK_PAIRING_COMPLETED = 0x5ABBCCEF,
+ WF_OK_PAIRING_FAILED = 0x3ABBCCF0,
+ WF_CANCELLED = 0x55667788,
+} workflow_result_t;
+
+workflow_result_t bootloader_process_usb(void);
+
+workflow_result_t bootloader_process_ble(void);
diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs
index 44bf3621..16be040d 100644
--- a/core/embed/rust/build.rs
+++ b/core/embed/rust/build.rs
@@ -26,6 +26,7 @@ fn build_dir() -> String {
}
const DEFAULT_BINDGEN_MACROS_COMMON: &[&str] = &[
+ "-I../projects/bootloader",
"-I../projects/unix",
"-I../../build/unix",
"-I../../vendor/micropython/ports/unix",
@@ -65,6 +66,7 @@ const DEFAULT_BINDGEN_MACROS_COMMON: &[&str] = &[
"-DUSE_HW_JPEG_DECODER",
"-DUSE_STORAGE",
"-DUSE_DBG_CONSOLE",
+ "-DBOOTLOADER",
];
fn add_bindgen_macros<'a>(
@@ -495,7 +497,9 @@ fn generate_trezorhal_bindings() {
.allowlist_var("LOG_LEVEL_WARN")
.allowlist_var("LOG_LEVEL_ERR")
// c_layout
- .allowlist_type("c_layout_t");
+ .allowlist_type("c_layout_t")
+ .allowlist_function("bootloader_process_ble")
+ .allowlist_function("bootloader_process_usb");
// Write the bindings to a file in the OUR_DIR.
bindings
diff --git a/core/embed/rust/rust_ui_bootloader.h b/core/embed/rust/rust_ui_bootloader.h
index c9100ee3..471f5ee6 100644
--- a/core/embed/rust/rust_ui_bootloader.h
+++ b/core/embed/rust/rust_ui_bootloader.h
@@ -8,15 +8,6 @@
// todo: use bindgen to bind return values to rust
-// send attach event to the layout
-uint32_t screen_attach(c_layout_t* layout);
-
-// common event function for screens that need UI + communication
-uint32_t screen_event(c_layout_t* layout, sysevents_t* signalled);
-
-// common render event
-void screen_render(c_layout_t* layout);
-
// result screens
void screen_wipe_success(void);
void screen_wipe_fail(void);
@@ -78,31 +69,35 @@ typedef enum {
MENU_BLUETOOTH = 0x99AABBCC,
MENU_POWER_OFF = 0x751A5BEF,
} menu_result_t;
-void screen_menu(bool initial_setup, c_layout_t* layout);
+uint32_t screen_menu(bool initial_setup, bool communication,
+ uint32_t* ui_result);
typedef enum {
CONNECT_CANCEL = 1,
CONNECT_PAIRING_MODE = 2,
CONNECT_MENU = 3,
} connect_result_t;
-void screen_connect(bool initial_setup, bool auto_update, c_layout_t* layout);
+uint32_t screen_connect(bool initial_setup, bool auto_update,
+ uint32_t* ui_result);
+
typedef enum {
WELCOME_CANCEL = 1,
WELCOME_PAIRING_MODE = 2,
WELCOME_MENU = 3,
} welcome_result_t;
-void screen_welcome(c_layout_t* layout);
+
+uint32_t screen_welcome(uint32_t* ui_result);
typedef enum {
// 0 - 999999 - pairing code
PAIRING_MODE_CANCEL = 1000000,
} pairing_mode_result_t;
-void screen_pairing_mode(bool initial_setup, const char* name, size_t name_len,
- c_layout_t* layout);
+uint32_t screen_pairing_mode(bool initial_setup, const char* name,
+ size_t name_len, uint32_t* ui_result);
typedef enum {
// 0 - 999999 - pairing code
WIRELESS_SETUP_CANCEL = 1000000,
} wireless_setup_result_t;
-void screen_wireless_setup(const char* name, size_t name_len,
- c_layout_t* layout);
+uint32_t screen_wireless_setup(const char* name, size_t name_len,
+ uint32_t* ui_result);
diff --git a/core/embed/rust/src/bootloader/mod.rs b/core/embed/rust/src/bootloader/mod.rs
new file mode 100644
index 00000000..e0e74f3f
--- /dev/null
+++ b/core/embed/rust/src/bootloader/mod.rs
@@ -0,0 +1,214 @@
+#[cfg(all(feature = "button", feature = "power_manager"))]
+use crate::ui::event::ButtonEvent;
+#[cfg(feature = "button")]
+use crate::ui::layout::simplified::button_eval;
+
+use crate::{
+ trezorhal::{
+ bootloader::{bootloader_process_usb, BootloaderWFResult},
+ sysevent::{sysevents_poll, Syshandle},
+ },
+ ui::{
+ component::{base::AttachType, Component, Event, EventCtx},
+ layout::simplified::{render, ReturnToC},
+ CommonUI, ModelUI,
+ },
+};
+
+#[cfg(feature = "ble")]
+use crate::trezorhal::bootloader::bootloader_process_ble;
+
+#[cfg(feature = "power_manager")]
+use crate::{
+ time::Instant,
+ trezorhal::power_manager::{hibernate, is_usb_connected, suspend},
+ ui::display::fade_backlight_duration,
+ ui::event::PhysicalButton,
+};
+
+#[cfg(all(feature = "haptic", feature = "power_manager"))]
+use crate::trezorhal::haptic::{play, HapticEffect};
+
+use heapless::Vec;
+
+#[cfg(feature = "power_manager")]
+use crate::time::Duration;
+#[cfg(feature = "power_manager")]
+const FADE_TIME: Duration = Duration::from_millis(30000);
+#[cfg(feature = "power_manager")]
+const SUSPEND_TIME: Duration = Duration::from_millis(40000);
+#[cfg(feature = "power_manager")]
+const HIBERNATE_TIME: Duration = Duration::from_millis(3000);
+
+pub fn run(
+ frame: &mut impl Component<Msg = impl ReturnToC>,
+ fade_transition: bool,
+ communication: bool,
+) -> (u32, u32) {
+ frame.place(ModelUI::SCREEN);
+
+ let e = Event::Attach(AttachType::Initial);
+ let mut ctx = EventCtx::new();
+
+ let msg = frame.event(&mut ctx, e);
+
+ if let Some(message) = msg {
+ return (
+ BootloaderWFResult::OkUiAction.return_to_c(),
+ message.return_to_c(),
+ );
+ }
+
+ if fade_transition {
+ ModelUI::fadeout();
+ }
+ render(frame);
+ ModelUI::fadein();
+
+ #[cfg(all(feature = "power_manager", feature = "haptic"))]
+ let mut haptic_played = false;
+ #[cfg(feature = "power_manager")]
+ let mut button_pressed_time = None;
+ #[cfg(feature = "power_manager")]
+ let mut start = Instant::now();
+ let mut faded = false;
+
+ // flush any pending events
+ #[cfg(feature = "button")]
+ while button_eval().is_some() {}
+
+ let mut ifaces: Vec<Syshandle, 16> = Vec::new();
+
+ #[cfg(feature = "ble")]
+ unwrap!(ifaces.push(Syshandle::Ble));
+
+ #[cfg(feature = "button")]
+ unwrap!(ifaces.push(Syshandle::Button));
+
+ #[cfg(feature = "touch")]
+ unwrap!(ifaces.push(Syshandle::Touch));
+
+ #[cfg(feature = "power_manager")]
+ unwrap!(ifaces.push(Syshandle::PowerManager));
+
+ if communication {
+ unwrap!(ifaces.push(Syshandle::UsbWire));
+
+ #[cfg(feature = "ble")]
+ unwrap!(ifaces.push(Syshandle::BleIface));
+ }
+
+ loop {
+ #[cfg(feature = "power_manager")]
+ let mut do_suspend = false;
+
+ #[cfg(all(feature = "power_manager", feature = "haptic"))]
+ {
+ if let Some(t) = button_pressed_time {
+ if let Some(elapsed) = Instant::now().checked_duration_since(t) {
+ if elapsed >= HIBERNATE_TIME && !haptic_played {
+ play(HapticEffect::BootloaderEntry);
+ haptic_played = true;
+ }
+ }
+ }
+ }
+
+ let event = sysevents_poll(ifaces.as_slice());
+
+ if let Some(e) = event {
+ if faded {
+ ModelUI::fadein();
+ faded = false;
+ }
+
+ if e == Event::USBWire {
+ let res = bootloader_process_usb();
+ if res == BootloaderWFResult::Ok {
+ continue;
+ }
+
+ return (res.return_to_c(), 0);
+ }
+
+ #[cfg(feature = "ble")]
+ if e == Event::BLEIface {
+ let res = bootloader_process_ble();
+ if res == BootloaderWFResult::Ok {
+ continue;
+ }
+
+ return (res.return_to_c(), 0);
+ }
+
+ #[cfg(feature = "power_manager")]
+ {
+ start = Instant::now();
+
+ if e == Event::Button(ButtonEvent::ButtonPressed(PhysicalButton::Power)) {
+ button_pressed_time = Some(Instant::now());
+
+ #[cfg(feature = "haptic")]
+ {
+ haptic_played = false;
+ }
+ } else if e == Event::Button(ButtonEvent::ButtonReleased(PhysicalButton::Power)) {
+ if let Some(t) = button_pressed_time {
+ if let Some(elapsed) = Instant::now().checked_duration_since(t) {
+ ModelUI::fadeout();
+ faded = true;
+ if elapsed >= HIBERNATE_TIME {
+ hibernate();
+ } else {
+ do_suspend = true;
+ }
+ }
+ }
+ }
+ }
+
+ let mut ctx = EventCtx::new();
+
+ let msg = frame.event(&mut ctx, e);
+
+ if let Some(message) = msg {
+ return (
+ BootloaderWFResult::OkUiAction.return_to_c(),
+ message.return_to_c(),
+ );
+ }
+ render(frame);
+ } else {
+ #[cfg(feature = "power_manager")]
+ {
+ if is_usb_connected() {
+ continue;
+ }
+
+ let elapsed = Instant::now().checked_duration_since(start);
+
+ if let Some(elapsed) = elapsed {
+ if elapsed >= FADE_TIME && !faded {
+ faded = true;
+ fade_backlight_duration(ModelUI::get_backlight_low(), 200);
+ }
+ if elapsed >= SUSPEND_TIME {
+ do_suspend = true;
+ }
+ }
+ }
+ }
+
+ #[cfg(feature = "power_manager")]
+ if do_suspend {
+ suspend();
+ render(frame);
+ if faded {
+ ModelUI::fadein();
+ faded = false;
+ }
+ start = Instant::now();
+ button_pressed_time = None;
+ }
+ }
+}
diff --git a/core/embed/rust/src/lib.rs b/core/embed/rust/src/lib.rs
index d48c6af4..d6bbb528 100644
--- a/core/embed/rust/src/lib.rs
+++ b/core/embed/rust/src/lib.rs
@@ -54,6 +54,9 @@ pub mod smp;
pub mod util;
+#[cfg(feature = "bootloader")]
+mod bootloader;
+
#[cfg(feature = "debug")]
#[cfg(not(test))]
#[panic_handler]
diff --git a/core/embed/rust/src/trezorhal/bootloader.rs b/core/embed/rust/src/trezorhal/bootloader.rs
new file mode 100644
index 00000000..5a5fbf63
--- /dev/null
+++ b/core/embed/rust/src/trezorhal/bootloader.rs
@@ -0,0 +1,33 @@
+use super::ffi;
+
+use num_traits::FromPrimitive;
+
+#[derive(PartialEq, Debug, Eq, Clone, Copy, FromPrimitive, ToPrimitive)]
+pub enum BootloaderWFResult {
+ ErrorFatal = ffi::workflow_result_t_WF_ERROR_FATAL as _,
+ Error = ffi::workflow_result_t_WF_ERROR as _,
+ Ok = ffi::workflow_result_t_WF_OK as _,
+ OkRebootSelected = ffi::workflow_result_t_WF_OK_REBOOT_SELECTED as _,
+ OkFirmwareInstalled = ffi::workflow_result_t_WF_OK_FIRMWARE_INSTALLED as _,
+ OkDeviceWiped = ffi::workflow_result_t_WF_OK_DEVICE_WIPED as _,
+ OkBootloaderUnlocked = ffi::workflow_result_t_WF_OK_BOOTLOADER_UNLOCKED as _,
+ OkUiAction = ffi::workflow_result_t_WF_OK_UI_ACTION as _,
+ OkPairingCompleted = ffi::workflow_result_t_WF_OK_PAIRING_COMPLETED as _,
+ OkPairingFailed = ffi::workflow_result_t_WF_OK_PAIRING_FAILED as _,
+ Cancelled = ffi::workflow_result_t_WF_CANCELLED as _,
+}
+
+pub fn bootloader_process_usb() -> BootloaderWFResult {
+ unsafe {
+ BootloaderWFResult::from_u32(ffi::bootloader_process_usb())
+ .unwrap_or(BootloaderWFResult::Error)
+ }
+}
+
+#[cfg(feature = "ble")]
+pub fn bootloader_process_ble() -> BootloaderWFResult {
+ unsafe {
+ BootloaderWFResult::from_u32(ffi::bootloader_process_ble())
+ .unwrap_or(BootloaderWFResult::Error)
+ }
+}
diff --git a/core/embed/rust/src/trezorhal/mod.rs b/core/embed/rust/src/trezorhal/mod.rs
index 06ac54b8..73929dfe 100644
--- a/core/embed/rust/src/trezorhal/mod.rs
+++ b/core/embed/rust/src/trezorhal/mod.rs
@@ -43,6 +43,9 @@ pub mod sysevent;
#[cfg(feature = "power_manager")]
pub mod power_manager;
+#[cfg(feature = "bootloader")]
+pub mod bootloader;
+
#[cfg(any(feature = "bootloader", feature = "prodtest"))]
pub mod layout_buf;
diff --git a/core/embed/rust/src/trezorhal/sysevent.rs b/core/embed/rust/src/trezorhal/sysevent.rs
index d674ef93..71b914c1 100644
--- a/core/embed/rust/src/trezorhal/sysevent.rs
+++ b/core/embed/rust/src/trezorhal/sysevent.rs
@@ -31,10 +31,17 @@ use crate::ui::event::ButtonEvent;
#[derive(PartialEq, Debug, Eq, Clone, Copy)]
pub enum Syshandle {
+ UsbWire = ffi::syshandle_t_SYSHANDLE_USB_WIRE as _,
+ UsbDebug = ffi::syshandle_t_SYSHANDLE_USB_DEBUG as _,
+ UsbWebauthn = ffi::syshandle_t_SYSHANDLE_USB_WEBAUTHN as _,
+ UsbVcp = ffi::syshandle_t_SYSHANDLE_USB_VCP as _,
+ BleIface = ffi::syshandle_t_SYSHANDLE_BLE_IFACE_0 as _,
+ PowerManager = ffi::syshandle_t_SYSHANDLE_POWER_MANAGER as _,
Button = ffi::syshandle_t_SYSHANDLE_BUTTON as _,
Touch = ffi::syshandle_t_SYSHANDLE_TOUCH as _,
+ Usb = ffi::syshandle_t_SYSHANDLE_USB as _,
Ble = ffi::syshandle_t_SYSHANDLE_BLE as _,
- PowerManager = ffi::syshandle_t_SYSHANDLE_POWER_MANAGER as _,
+ Syscall = ffi::syshandle_t_SYSHANDLE_SYSCALL as _,
}
impl Syshandle {
@@ -139,6 +146,19 @@ pub fn parse_event(signalled: &sysevents_t) -> Option<Event> {
}
}
+ if signalled.read_ready & (1 << ffi::syshandle_t_SYSHANDLE_USB_WIRE) != 0 {
+ return Some(Event::USBWire);
+ }
+
+ if signalled.read_ready & (1 << ffi::syshandle_t_SYSHANDLE_USB_DEBUG) != 0 {
+ return Some(Event::USBDebug);
+ }
+
+ #[cfg(feature = "ble")]
+ if signalled.read_ready & (1 << ffi::syshandle_t_SYSHANDLE_BLE_IFACE_0) != 0 {
+ return Some(Event::BLEIface);
+ }
+
None
}
@@ -147,7 +167,13 @@ pub fn sysevents_poll(ifaces: &[Syshandle]) -> Option<Event> {
let mut signalled = Sysevents::zeroed();
// SAFETY: safe.
- unsafe { ffi::sysevents_poll(&awaited as _, &mut signalled as _, ticks_ms() + 100) };
+ unsafe {
+ ffi::sysevents_poll(
+ &awaited as _,
+ &mut signalled as _,
+ ticks_ms().wrapping_add(100),
+ )
+ };
parse_event(&signalled)
}
diff --git a/core/embed/rust/src/ui/api/bootloader_c.rs b/core/embed/rust/src/ui/api/bootloader_c.rs
index 4a390f5c..89855e89 100644
--- a/core/embed/rust/src/ui/api/bootloader_c.rs
+++ b/core/embed/rust/src/ui/api/bootloader_c.rs
@@ -1,54 +1,16 @@
use crate::{
strutil::hexlify,
- trezorhal::{
- layout_buf::{c_layout_t, LayoutBuffer},
- sysevent::{parse_event, sysevents_t},
- },
- ui::{
- ui_bootloader::{BootloaderLayoutType as _, BootloaderUI},
- ModelUI,
- },
+ ui::{ui_bootloader::BootloaderUI, ModelUI},
util::{from_c_array, from_c_str},
};
#[no_mangle]
-extern "C" fn screen_attach(layout: *mut c_layout_t) -> u32 {
- // SAFETY: calling code is supposed to give us exclusive access to an already
- // initialized layout
+extern "C" fn screen_welcome(ui_action_result: *mut u32) -> u32 {
+ let (res, ui_res) = ModelUI::screen_welcome();
unsafe {
- let mut layout = LayoutBuffer::<<ModelUI as BootloaderUI>::CLayoutType>::new(layout);
- let layout = layout.get_mut();
- layout.show()
+ *ui_action_result = ui_res;
}
-}
-
-#[no_mangle]
-extern "C" fn screen_event(layout: *mut c_layout_t, signalled: &sysevents_t) -> u32 {
- let e = parse_event(signalled);
- // SAFETY: calling code is supposed to give us exclusive access to an already
- // initialized layout
- unsafe {
- let mut layout = LayoutBuffer::<<ModelUI as BootloaderUI>::CLayoutType>::new(layout);
- let layout = layout.get_mut();
- layout.event(e)
- }
-}
-
-#[no_mangle]
-extern "C" fn screen_render(layout: *mut c_layout_t) {
- unsafe {
- let mut layout = LayoutBuffer::<<ModelUI as BootloaderUI>::CLayoutType>::new(layout);
- let layout = layout.get_mut();
- layout.render()
- }
-}
-
-#[no_mangle]
-extern "C" fn screen_welcome(layout: *mut c_layout_t) {
- let screen = <ModelUI as BootloaderUI>::CLayoutType::init_welcome();
- // SAFETY: calling code is supposed to give us exclusive access to the layout
- let mut layout = unsafe { LayoutBuffer::new(layout) };
- layout.store(screen);
+ res
}
#[no_mangle]
@@ -113,11 +75,16 @@ extern "C" fn screen_unlock_bootloader_success() {
}
#[no_mangle]
-extern "C" fn screen_menu(initial_setup: bool, layout: *mut c_layout_t) {
- let screen = <ModelUI as BootloaderUI>::CLayoutType::init_menu(initial_setup);
- // SAFETY: calling code is supposed to give us exclusive access to the layout
- let mut layout = unsafe { LayoutBuffer::new(layout) };
- layout.store(screen);
+extern "C" fn screen_menu(
+ initial_setup: bool,
+ communication: bool,
+ ui_action_result: *mut u32,
+) -> u32 {
+ let (res, ui_res) = ModelUI::screen_menu(initial_setup, communication);
+ unsafe {
+ *ui_action_result = ui_res;
+ }
+ res
}
#[no_mangle]
@@ -182,11 +149,16 @@ extern "C" fn screen_install_progress(
}
#[no_mangle]
-extern "C" fn screen_connect(initial_setup: bool, auto_update: bool, layout: *mut c_layout_t) {
- let screen = <ModelUI as BootloaderUI>::CLayoutType::init_connect(initial_setup, auto_update);
- // SAFETY: calling code is supposed to give us exclusive access to the layout
- let mut layout = unsafe { LayoutBuffer::new(layout) };
- layout.store(screen);
+extern "C" fn screen_connect(
+ initial_setup: bool,
+ auto_update: bool,
+ ui_action_result: *mut u32,
+) -> u32 {
+ let (res, ui_res) = ModelUI::screen_connect(initial_setup, auto_update);
+ unsafe {
+ *ui_action_result = ui_res;
+ }
+ res
}
#[no_mangle]
@@ -211,13 +183,15 @@ extern "C" fn screen_pairing_mode(
initial_setup: bool,
name: *const cty::c_char,
name_len: usize,
- layout: *mut c_layout_t,
-) {
+ ui_action_result: *mut u32,
+) -> u32 {
let name = unsafe { from_c_array(name, name_len).unwrap_or("") };
- let screen = <ModelUI as BootloaderUI>::CLayoutType::init_pairing_mode(initial_setup, name);
- // SAFETY: calling code is supposed to give us exclusive access to the layout
- let mut layout = unsafe { LayoutBuffer::new(layout) };
- layout.store(screen);
+
+ let (res, ui_res) = ModelUI::screen_pairing_mode(initial_setup, name);
+ unsafe {
+ *ui_action_result = ui_res;
+ }
+ res
}
#[cfg(feature = "ble")]
@@ -225,13 +199,15 @@ extern "C" fn screen_pairing_mode(
extern "C" fn screen_wireless_setup(
name: *const cty::c_char,
name_len: usize,
- layout: *mut c_layout_t,
-) {
+ ui_action_result: *mut u32,
+) -> u32 {
let name = unsafe { from_c_array(name, name_len).unwrap_or("") };
- let screen = <ModelUI as BootloaderUI>::CLayoutType::init_wireless_setup(name);
- // SAFETY: calling code is supposed to give us exclusive access to the layout
- let mut layout = unsafe { LayoutBuffer::new(layout) };
- layout.store(screen);
+
+ let (res, ui_res) = ModelUI::screen_wireless_setup(name);
+ unsafe {
+ *ui_action_result = ui_res;
+ }
+ res
}
#[cfg(feature = "ble")]
diff --git a/core/embed/rust/src/ui/component/base.rs b/core/embed/rust/src/ui/component/base.rs
index d43ca780..b0503f72 100644
--- a/core/embed/rust/src/ui/component/base.rs
+++ b/core/embed/rust/src/ui/component/base.rs
@@ -329,6 +329,10 @@ pub enum Event {
BLE(BLEEvent),
#[cfg(feature = "power_manager")]
PM(PMEvent),
+ USBWire,
+ USBDebug,
+ #[cfg(feature = "ble")]
+ BLEIface,
USB(USBEvent),
/// Previously requested timer was triggered. This invalidates the timer
/// token (another timer has to be requested).
diff --git a/core/embed/rust/src/ui/layout/simplified.rs b/core/embed/rust/src/ui/layout/simplified.rs
index db7bdc60..3c9b0d12 100644
--- a/core/embed/rust/src/ui/layout/simplified.rs
+++ b/core/embed/rust/src/ui/layout/simplified.rs
@@ -11,27 +11,8 @@ use crate::ui::{
use crate::ui::{component::Event, display::color::Color, shape::render_on_display};
-use crate::trezorhal::sysevent::{sysevents_poll, Syshandle};
-
-#[cfg(feature = "power_manager")]
-use crate::{
- time::{Duration, Instant},
- trezorhal::power_manager::{hibernate, is_usb_connected, suspend},
- ui::display::fade_backlight_duration,
- ui::event::PhysicalButton,
-};
-
-#[cfg(all(feature = "haptic", feature = "power_manager"))]
-use crate::trezorhal::haptic::{play, HapticEffect};
-
-use heapless::Vec;
use num_traits::ToPrimitive;
-#[cfg(feature = "power_manager")]
-const FADE_TIME: Duration = Duration::from_millis(30000);
-#[cfg(feature = "power_manager")]
-const SUSPEND_TIME: Duration = Duration::from_millis(40000);
-
pub trait ReturnToC {
fn return_to_c(self) -> u32;
}
@@ -52,7 +33,7 @@ where
}
#[cfg(feature = "button")]
-fn button_eval() -> Option<ButtonEvent> {
+pub fn button_eval() -> Option<ButtonEvent> {
let event = button_get_event();
let (event_btn, event_type) = event?;
let event = ButtonEvent::new(event_type, event_btn);
@@ -101,145 +82,6 @@ where
0
}
-pub fn run(frame: &mut impl Component<Msg = impl ReturnToC>) -> u32 {
- frame.place(ModelUI::SCREEN);
-
- let e = Event::Attach(AttachType::Initial);
- let mut ctx = EventCtx::new();
-
- let msg = frame.event(&mut ctx, e);
-
- if let Some(message) = msg {
- return message.return_to_c();
- }
-
- ModelUI::fadeout();
- render(frame);
- ModelUI::fadein();
-
- #[cfg(all(feature = "power_manager", feature = "haptic"))]
- let mut haptic_played = false;
- #[cfg(feature = "power_manager")]
- let mut button_pressed_time = None;
- #[cfg(feature = "power_manager")]
- let mut start = Instant::now();
- let mut faded = false;
-
- // flush any pending events
- #[cfg(feature = "button")]
- while button_eval().is_some() {}
-
- let mut ifaces: Vec<Syshandle, 16> = Vec::new();
-
- #[cfg(feature = "ble")]
- unwrap!(ifaces.push(Syshandle::Ble));
-
- #[cfg(feature = "button")]
- unwrap!(ifaces.push(Syshandle::Button));
-
- #[cfg(feature = "touch")]
- unwrap!(ifaces.push(Syshandle::Touch));
-
- #[cfg(feature = "power_manager")]
- unwrap!(ifaces.push(Syshandle::PowerManager));
-
- loop {
- let event = sysevents_poll(ifaces.as_slice());
-
- if let Some(e) = event {
- if faded {
- ModelUI::fadein();
- faded = false;
- }
-
- #[cfg(feature = "power_manager")]
- {
- start = Instant::now();
-
- if e == Event::Button(ButtonEvent::ButtonPressed(PhysicalButton::Power)) {
- button_pressed_time = Some(Instant::now());
-
- #[cfg(feature = "haptic")]
- {
- haptic_played = false;
- }
- } else if e == Event::Button(ButtonEvent::ButtonReleased(PhysicalButton::Power)) {
- if let Some(t) = button_pressed_time {
- if let Some(elapsed) = Instant::now().checked_duration_since(t) {
- ModelUI::fadeout();
- if elapsed.to_secs() >= 3 {
- #[cfg(feature = "haptic")]
- {
- if !haptic_played {
- play(HapticEffect::BootloaderEntry);
- haptic_played = true;
- }
- }
- hibernate();
- } else {
- suspend();
- render(frame);
- ModelUI::fadein();
-
- faded = false;
- button_pressed_time = None;
- start = Instant::now();
- }
- }
- }
- }
- }
-
- let mut ctx = EventCtx::new();
-
- let msg = frame.event(&mut ctx, e);
-
- if let Some(message) = msg {
- return message.return_to_c();
- }
- render(frame);
- } else {
- #[cfg(feature = "power_manager")]
- {
- #[cfg(feature = "haptic")]
- {
- if let Some(t) = button_pressed_time {
- if let Some(elapsed) = Instant::now().checked_duration_since(t) {
- if elapsed.to_secs() >= 3 && !haptic_played {
- play(HapticEffect::BootloaderEntry);
- haptic_played = true;
- }
- }
- }
- }
-
- if is_usb_connected() {
- continue;
- }
-
- let elapsed = Instant::now().checked_duration_since(start);
-
- if let Some(elapsed) = elapsed {
- if elapsed >= FADE_TIME && !faded {
- faded = true;
- fade_backlight_duration(ModelUI::get_backlight_low(), 200);
- }
- if elapsed >= SUSPEND_TIME {
- suspend();
- render(frame);
- if faded {
- ModelUI::fadein();
- faded = false;
- }
- start = Instant::now();
- button_pressed_time = None;
- }
- }
- }
- }
- }
-}
-
pub fn show(frame: &mut impl Component<Msg = impl ReturnToC>, fading: bool) -> u32 {
frame.place(ModelUI::SCREEN);
diff --git a/core/embed/rust/src/ui/layout_bolt/bootloader/mod.rs b/core/embed/rust/src/ui/layout_bolt/bootloader/mod.rs
index 221370ac..e308392f 100644
--- a/core/embed/rust/src/ui/layout_bolt/bootloader/mod.rs
+++ b/core/embed/rust/src/ui/layout_bolt/bootloader/mod.rs
@@ -30,15 +30,16 @@ use super::{
UIBolt,
};
use crate::{
+ bootloader::run,
time::Duration,
trezorhal::time,
ui::{
- component::{Event, Label},
+ component::Label,
display::{self, toif::Toif, Color, Icon, LOADER_MAX},
geometry::{Alignment, Alignment2D, Offset, Point, Rect},
- layout::simplified::{process_frame_event, run, show},
+ layout::simplified::show,
shape::{self, render_on_display},
- ui_bootloader::{BootloaderLayoutType, BootloaderUI},
+ ui_bootloader::BootloaderUI,
CommonUI,
},
};
@@ -136,85 +137,29 @@ impl UIBolt {
}
}
-#[allow(clippy::large_enum_variant)]
-pub enum BootloaderLayout {
- Welcome(Welcome),
- Menu(Menu),
- Connect(Connect),
- #[cfg(feature = "ble")]
- PairingMode(PairingMode),
-}
-
-impl BootloaderLayoutType for BootloaderLayout {
- fn event(&mut self, event: Option<Event>) -> u32 {
- match self {
- BootloaderLayout::Welcome(f) => process_frame_event::<Welcome>(f, event),
- BootloaderLayout::Menu(f) => process_frame_event::<Menu>(f, event),
- BootloaderLayout::Connect(f) => process_frame_event::<Connect>(f, event),
- #[cfg(feature = "ble")]
- BootloaderLayout::PairingMode(f) => process_frame_event::<PairingMode>(f, event),
- }
- }
-
- fn show(&mut self) -> u32 {
- match self {
- BootloaderLayout::Welcome(f) => show(f, true),
- BootloaderLayout::Menu(f) => show(f, true),
- BootloaderLayout::Connect(f) => show(f, true),
- #[cfg(feature = "ble")]
- BootloaderLayout::PairingMode(f) => show(f, true),
- }
- }
-
- fn init_welcome() -> Self {
+impl BootloaderUI for UIBolt {
+ fn screen_welcome() -> (u32, u32) {
// let the previous screen on for some time
time::sleep(Duration::from_millis(1000));
- Self::Welcome(Welcome::new())
+ let mut frame = Welcome::new();
+ run(&mut frame, true, true)
}
-
- fn init_menu(_initial_setup: bool) -> Self {
- Self::Menu(Menu::new())
+ fn screen_menu(_initial_setup: bool, communication: bool) -> (u32, u32) {
+ let mut frame = Menu::new();
+ run(&mut frame, true, communication)
}
- fn init_connect(initial_setup: bool, auto_update: bool) -> Self {
- let frame = Connect::new(
+ fn screen_connect(initial_setup: bool, auto_update: bool) -> (u32, u32) {
+ let mut frame = Connect::new(
"Waiting for host...",
fonts::FONT_NORMAL,
BLD_TITLE_COLOR,
initial_setup,
auto_update,
);
- Self::Connect(frame)
- }
-
- #[cfg(feature = "ble")]
- fn init_pairing_mode(initial_setup: bool, _name: &'static str) -> Self {
- let bg = if initial_setup { WELCOME_COLOR } else { BLD_BG };
-
- let btn = if initial_setup {
- Button::with_text("Cancel".into()).styled(button_initial())
- } else {
- Button::with_text("Cancel".into()).styled(button_bld())
- };
-
- let frame = PairingMode::new(
- "Waiting for pairing...".into(),
- fonts::FONT_NORMAL,
- BLD_TITLE_COLOR,
- bg,
- btn,
- );
- Self::PairingMode(frame)
+ run(&mut frame, true, true)
}
- #[cfg(feature = "ble")]
- fn init_wireless_setup(_name: &'static str) -> Self {
- unimplemented!()
- }
-}
-
-impl BootloaderUI for UIBolt {
- type CLayoutType = BootloaderLayout;
fn screen_install_success(restart_seconds: u8, initial_setup: bool, complete_draw: bool) {
let mut reboot_msg = BootloaderString::new();
@@ -300,7 +245,8 @@ impl BootloaderUI for UIBolt {
frame = frame.with_alert(alert);
}
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_wipe_confirm() -> u32 {
@@ -318,7 +264,8 @@ impl BootloaderUI for UIBolt {
let mut frame = Confirm::new(BLD_WIPE_COLOR, left, right, ConfirmTitle::Icon(icon), msg)
.with_alert(alert);
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_unlock_bootloader_confirm() -> u32 {
@@ -346,7 +293,8 @@ impl BootloaderUI for UIBolt {
fw_ok,
);
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_boot_stage_1(fading: bool) {
@@ -403,7 +351,7 @@ impl BootloaderUI for UIBolt {
.vertically_centered(),
true,
);
- run(&mut frame);
+ run(&mut frame, true, false);
}
fn screen_wipe_fail() {
@@ -502,6 +450,26 @@ impl BootloaderUI for UIBolt {
display::refresh();
}
+ #[cfg(feature = "ble")]
+ fn screen_pairing_mode(initial_setup: bool, _name: &'static str) -> (u32, u32) {
+ let bg = if initial_setup { WELCOME_COLOR } else { BLD_BG };
+
+ let btn = if initial_setup {
+ Button::with_text("Cancel".into()).styled(button_initial())
+ } else {
+ Button::with_text("Cancel".into()).styled(button_bld())
+ };
+
+ let mut frame = PairingMode::new(
+ "Waiting for pairing...".into(),
+ fonts::FONT_NORMAL,
+ BLD_TITLE_COLOR,
+ bg,
+ btn,
+ );
+ run(&mut frame, true, false)
+ }
+
#[cfg(feature = "ble")]
fn screen_confirm_pairing(code: u32, initial_setup: bool) -> u32 {
let bg = if initial_setup { WELCOME_COLOR } else { BLD_BG };
@@ -521,7 +489,8 @@ impl BootloaderUI for UIBolt {
let mut frame = ConfirmPairing::new(bg, left, right, title, code);
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
#[cfg(feature = "ble")]
@@ -542,6 +511,7 @@ impl BootloaderUI for UIBolt {
btn,
);
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
}
diff --git a/core/embed/rust/src/ui/layout_caesar/bootloader/mod.rs b/core/embed/rust/src/ui/layout_caesar/bootloader/mod.rs
index be2da7f6..622acfd0 100644
--- a/core/embed/rust/src/ui/layout_caesar/bootloader/mod.rs
+++ b/core/embed/rust/src/ui/layout_caesar/bootloader/mod.rs
@@ -5,8 +5,7 @@ use crate::ui::{
constant::{self, HEIGHT, SCREEN},
display::{self, Color, Icon},
geometry::{Alignment2D, Offset, Point},
- layout::simplified::{run, show, ReturnToC},
- ui_bootloader::BootloaderLayoutType,
+ layout::simplified::{show, ReturnToC},
};
use super::{
@@ -22,7 +21,10 @@ use super::{
UICaesar,
};
-use crate::ui::{display::toif::Toif, geometry::Alignment, shape, shape::render_on_display};
+use crate::{
+ bootloader::run,
+ ui::{display::toif::Toif, geometry::Alignment, shape, shape::render_on_display},
+};
use ufmt::uwrite;
@@ -32,11 +34,7 @@ mod welcome;
mod connect;
-use crate::{
- time::Duration,
- trezorhal::time,
- ui::{component::Event, layout::simplified::process_frame_event, ui_bootloader::BootloaderUI},
-};
+use crate::{time::Duration, trezorhal::time, ui::ui_bootloader::BootloaderUI};
use connect::Connect;
use intro::Intro;
use menu::Menu;
@@ -93,61 +91,24 @@ impl UICaesar {
}
}
-pub enum BootloaderLayout {
- Welcome(Welcome),
- Menu(Menu),
- Connect(Connect),
-}
-
-impl BootloaderLayoutType for BootloaderLayout {
- fn event(&mut self, event: Option<Event>) -> u32 {
- match self {
- BootloaderLayout::Welcome(f) => process_frame_event::<Welcome>(f, event),
- BootloaderLayout::Menu(f) => process_frame_event::<Menu>(f, event),
- BootloaderLayout::Connect(f) => process_frame_event::<Connect>(f, event),
- }
- }
-
- fn show(&mut self) -> u32 {
- match self {
- BootloaderLayout::Welcome(f) => show(f, false),
- BootloaderLayout::Menu(f) => show(f, false),
- BootloaderLayout::Connect(f) => show(f, false),
- }
- }
-
- fn init_welcome() -> Self {
+impl BootloaderUI for UICaesar {
+ fn screen_welcome() -> (u32, u32) {
// let the previous screen on for some time
time::sleep(Duration::from_millis(1500));
- Self::Welcome(Welcome::new())
+ let mut frame = Welcome::new();
+ run(&mut frame, true, true)
}
- fn init_menu(_initial_setup: bool) -> Self {
- Self::Menu(Menu::new())
+ fn screen_menu(_initial_setup: bool, communication: bool) -> (u32, u32) {
+ let mut frame = Menu::new();
+ run(&mut frame, true, communication)
}
- fn init_connect(_initial_setup: bool, _auto_update: bool) -> Self {
- Self::Connect(Connect::new(
- "Waiting for host...",
- fonts::FONT_NORMAL,
- BLD_FG,
- BLD_BG,
- ))
- }
+ fn screen_connect(_initial_setup: bool, _auto_update: bool) -> (u32, u32) {
+ let mut frame = Connect::new("Waiting for host...", fonts::FONT_NORMAL, BLD_FG, BLD_BG);
- #[cfg(feature = "ble")]
- fn init_pairing_mode(_initial_setup: bool, _name: &'static str) -> Self {
- unimplemented!()
- }
-
- #[cfg(feature = "ble")]
- fn init_wireless_setup(_name: &'static str) -> Self {
- unimplemented!()
+ run(&mut frame, true, true)
}
-}
-
-impl BootloaderUI for UICaesar {
- type CLayoutType = BootloaderLayout;
fn screen_install_success(restart_seconds: u8, _initial_setup: bool, complete_draw: bool) {
let mut reboot_msg = BootloaderString::new();
@@ -230,7 +191,9 @@ impl BootloaderUI for UICaesar {
false,
)
.with_info_screen("FW FINGERPRINT".into(), fingerprint);
- run(&mut frame)
+
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_wipe_confirm() -> u32 {
@@ -246,7 +209,8 @@ impl BootloaderUI for UICaesar {
false,
);
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_unlock_bootloader_confirm() -> u32 {
@@ -265,7 +229,8 @@ impl BootloaderUI for UICaesar {
true,
);
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_unlock_bootloader_success() {
@@ -275,7 +240,8 @@ impl BootloaderUI for UICaesar {
.vertically_centered();
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SPINNER, title, content, true);
- run(&mut frame);
+
+ run(&mut frame, true, false);
}
fn screen_intro(bld_version: &str, vendor: &str, version: &str, fw_ok: bool) -> u32 {
@@ -294,7 +260,9 @@ impl BootloaderUI for UICaesar {
version_str.as_str().into(),
fw_ok,
);
- run(&mut frame)
+
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_boot_stage_1(_fading: bool) {
@@ -338,7 +306,8 @@ impl BootloaderUI for UICaesar {
.vertically_centered();
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SPINNER, title, content, true);
- run(&mut frame);
+
+ run(&mut frame, true, false);
}
fn screen_wipe_fail() {
diff --git a/core/embed/rust/src/ui/layout_delizia/bootloader/mod.rs b/core/embed/rust/src/ui/layout_delizia/bootloader/mod.rs
index b70855a8..9205374f 100644
--- a/core/embed/rust/src/ui/layout_delizia/bootloader/mod.rs
+++ b/core/embed/rust/src/ui/layout_delizia/bootloader/mod.rs
@@ -1,13 +1,5 @@
use heapless::String;
-use crate::ui::{
- component::Label,
- display::{self, Color, Icon},
- geometry::{Alignment, Offset, Point, Rect},
- layout::simplified::{run, show},
- ui_bootloader::BootloaderLayoutType,
-};
-
use super::{
bootloader::welcome::Welcome,
component::{
@@ -20,32 +12,33 @@ use super::{
backlight,
bootloader::{
button_bld, button_bld_menu, button_confirm, button_wipe_cancel, button_wipe_confirm,
- BLD_BG, BLD_FG, BLD_TITLE_COLOR, BLD_WIPE_COLOR, CHECK24, CHECK40, DOWNLOAD24, FIRE32,
- FIRE40, RESULT_FW_INSTALL, RESULT_WIPE, TEXT_BOLD, TEXT_NORMAL, TEXT_WIPE_BOLD,
- TEXT_WIPE_NORMAL, WARNING40, WELCOME_COLOR, X24,
+ BLD_BG, BLD_FG, BLD_TITLE_COLOR, BLD_WARN_COLOR, BLD_WIPE_COLOR, CHECK24, CHECK40,
+ DOWNLOAD24, FIRE32, FIRE40, RESULT_FW_INSTALL, RESULT_WIPE, TEXT_BOLD, TEXT_NORMAL,
+ TEXT_WIPE_BOLD, TEXT_WIPE_NORMAL, WARNING40, WELCOME_COLOR, X24,
},
GREEN_LIGHT, GREY,
},
UIDelizia,
};
-use crate::ui::{ui_bootloader::BootloaderUI, CommonUI};
-
-use crate::ui::{
- display::{toif::Toif, LOADER_MAX},
- geometry::Alignment2D,
- shape,
- shape::render_on_display,
-};
-
-use ufmt::uwrite;
-
-use super::theme::bootloader::BLD_WARN_COLOR;
use crate::{
+ bootloader::run,
time::Duration,
trezorhal::time,
- ui::{component::Event, layout::simplified::process_frame_event},
+ ui::{
+ component::Label,
+ display::{self, toif::Toif, Color, Icon, LOADER_MAX},
+ geometry::{Alignment, Alignment2D, Offset, Point, Rect},
+ layout::simplified::show,
+ shape,
+ shape::render_on_display,
+ ui_bootloader::BootloaderUI,
+ CommonUI,
+ },
};
+
+use ufmt::uwrite;
+
use connect::Connect;
use intro::Intro;
use menu::Menu;
@@ -128,60 +121,28 @@ impl UIDelizia {
}
}
-#[allow(clippy::large_enum_variant)]
-pub enum BootloaderLayout {
- Welcome(Welcome),
- Menu(Menu),
- Connect(Connect),
-}
-
-impl BootloaderLayoutType for BootloaderLayout {
- fn event(&mut self, event: Option<Event>) -> u32 {
- match self {
- BootloaderLayout::Welcome(f) => process_frame_event::<Welcome>(f, event),
- BootloaderLayout::Menu(f) => process_frame_event::<Menu>(f, event),
- BootloaderLayout::Connect(f) => process_frame_event::<Connect>(f, event),
- }
- }
-
- fn show(&mut self) -> u32 {
- match self {
- BootloaderLayout::Welcome(f) => show(f, true),
- BootloaderLayout::Menu(f) => show(f, true),
- BootloaderLayout::Connect(f) => show(f, true),
- }
- }
- fn init_welcome() -> Self {
+impl BootloaderUI for UIDelizia {
+ fn screen_welcome() -> (u32, u32) {
// let the previous screen on for some time
time::sleep(Duration::from_millis(1500));
- Self::Welcome(Welcome::new())
+ let mut frame = Welcome::new();
+ run(&mut frame, true, true)
}
- fn init_menu(_initial_setup: bool) -> Self {
- Self::Menu(Menu::new())
+ fn screen_menu(_initial_setup: bool, communication: bool) -> (u32, u32) {
+ let mut frame = Menu::new();
+ run(&mut frame, true, communication)
}
- fn init_connect(_initial_setup: bool, _auto_update: bool) -> Self {
- Self::Connect(Connect::new(
+ fn screen_connect(_initial_setup: bool, _auto_update: bool) -> (u32, u32) {
+ let mut frame = Connect::new(
"Waiting for host...",
fonts::FONT_DEMIBOLD,
BLD_TITLE_COLOR,
BLD_BG,
- ))
- }
-
- #[cfg(feature = "ble")]
- fn init_pairing_mode(_initial_setup: bool, _name: &'static str) -> Self {
- unimplemented!()
- }
-
- #[cfg(feature = "ble")]
- fn init_wireless_setup(_name: &'static str) -> Self {
- unimplemented!()
+ );
+ run(&mut frame, true, true)
}
-}
-impl BootloaderUI for UIDelizia {
- type CLayoutType = BootloaderLayout;
fn screen_install_success(restart_seconds: u8, initial_setup: bool, complete_draw: bool) {
let mut reboot_msg = BootloaderString::new();
@@ -291,7 +252,8 @@ impl BootloaderUI for UIDelizia {
frame = frame.with_alert(alert);
}
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_wipe_confirm() -> u32 {
@@ -313,7 +275,8 @@ impl BootloaderUI for UIDelizia {
let mut frame = Confirm::new(BLD_WIPE_COLOR, left, right, ConfirmTitle::Icon(icon), msg)
.with_alert(alert);
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_unlock_bootloader_confirm() -> u32 {
@@ -333,7 +296,8 @@ impl BootloaderUI for UIDelizia {
let mut frame = Confirm::new(BLD_BG, left, right, ConfirmTitle::Text(title), msg);
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_unlock_bootloader_success() {
@@ -345,7 +309,7 @@ impl BootloaderUI for UIDelizia {
.vertically_centered(),
true,
);
- run(&mut frame);
+ run(&mut frame, true, false);
}
fn screen_intro(bld_version: &str, vendor: &str, version: &str, fw_ok: bool) -> u32 {
@@ -365,7 +329,8 @@ impl BootloaderUI for UIDelizia {
fw_ok,
);
- run(&mut frame)
+ let (_, res) = run(&mut frame, true, false);
+ res
}
fn screen_boot_stage_1(fading: bool) {
@@ -425,7 +390,7 @@ impl BootloaderUI for UIDelizia {
.vertically_centered(),
true,
);
- run(&mut frame);
+ run(&mut frame, true, false);
}
fn screen_wipe_fail() {
diff --git a/core/embed/rust/src/ui/layout_eckhart/ui_bootloader.rs b/core/embed/rust/src/ui/layout_eckhart/ui_bootloader.rs
index 6b87b149..a568e902 100644
--- a/core/embed/rust/src/ui/layout_eckhart/ui_bootloader.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/ui_bootloader.rs
@@ -1,11 +1,14 @@
-use crate::ui::{
- component::{base::Component, text::TextStyle, Event, Label},
- display::{self, toif::Toif, Color},
- geometry::{Alignment, Alignment2D, Offset, Point, Rect},
- layout::simplified::{process_frame_event, render, run, show},
- shape::{self, render_on_display},
- ui_bootloader::{BootloaderLayoutType, BootloaderUI},
- CommonUI,
+use crate::{
+ bootloader::run,
+ ui::{
+ component::{base::Component, text::TextStyle, Label},
+ display::{self, toif::Toif, Color},
+ geometry::{Alignment, Alignment2D, Offset, Point, Rect},
+ layout::simplified::show,
+ shape::{self, render_on_display},
+ ui_bootloader::BootloaderUI,
+ CommonUI,
+ },
};
use heapless::String;
@@ -89,70 +92,21 @@ impl UIEckhart {
}
}
-#[allow(clippy::large_enum_variant)]
-pub enum BootloaderLayout {
- Welcome(BldWelcomeScreen),
- Menu(BldMenuScreen),
- Connect(ConnectScreen),
- #[cfg(feature = "ble")]
- PairingMode(PairingModeScreen),
- #[cfg(feature = "ble")]
- WirelessSetup(WirelessSetupScreen),
-}
-
-impl BootloaderLayoutType for BootloaderLayout {
- fn event(&mut self, event: Option<Event>) -> u32 {
- match self {
- BootloaderLayout::Welcome(f) => process_frame_event::<BldWelcomeScreen>(f, event),
- BootloaderLayout::Menu(f) => process_frame_event::<BldMenuScreen>(f, event),
- BootloaderLayout::Connect(f) => process_frame_event::<ConnectScreen>(f, event),
- #[cfg(feature = "ble")]
- BootloaderLayout::PairingMode(f) => process_frame_event::<PairingModeScreen>(f, event),
- #[cfg(feature = "ble")]
- BootloaderLayout::WirelessSetup(f) => {
- process_frame_event::<WirelessSetupScreen>(f, event)
- }
- }
- }
-
- fn render(&mut self) {
- match self {
- BootloaderLayout::Welcome(f) => render(f),
- BootloaderLayout::Menu(f) => render(f),
- BootloaderLayout::Connect(f) => render(f),
- #[cfg(feature = "ble")]
- BootloaderLayout::PairingMode(f) => render(f),
- #[cfg(feature = "ble")]
- BootloaderLayout::WirelessSetup(f) => render(f),
- }
- }
-
- fn show(&mut self) -> u32 {
- match self {
- BootloaderLayout::Welcome(f) => show(f, false),
- BootloaderLayout::Menu(f) => show(f, true),
- BootloaderLayout::Connect(f) => show(f, true),
- #[cfg(feature = "ble")]
- BootloaderLayout::PairingMode(f) => show(f, true),
- #[cfg(feature = "ble")]
- BootloaderLayout::WirelessSetup(f) => show(f, true),
- }
- }
-
- fn init_welcome() -> Self {
- let screen = BldWelcomeScreen::new();
- Self::Welcome(screen)
+impl BootloaderUI for UIEckhart {
+ fn screen_welcome() -> (u32, u32) {
+ let mut screen = BldWelcomeScreen::new();
+ run(&mut screen, false, true)
}
- fn init_menu(initial_setup: bool) -> Self {
+ fn screen_menu(initial_setup: bool, communication: bool) -> (u32, u32) {
let mut screen = BldMenuScreen::new();
if !initial_setup {
screen = screen.with_screen_border(SCREEN_BORDER_BLUE);
}
- Self::Menu(screen)
+ run(&mut screen, true, communication)
}
- fn init_connect(initial_setup: bool, auto_update: bool) -> Self {
+ fn screen_connect(initial_setup: bool, auto_update: bool) -> (u32, u32) {
let mut screen = ConnectScreen::new(initial_setup);
if auto_update {
screen = screen.with_header(BldHeader::new("Bootloader".into()).with_menu_button());
@@ -160,27 +114,23 @@ impl BootloaderLayoutType for BootloaderLayout {
if !initial_setup {
screen = screen.with_screen_border(SCREEN_BORDER_BLUE);
}
- Self::Connect(screen)
+ run(&mut screen, true, true)
}
#[cfg(feature = "ble")]
- fn init_pairing_mode(initial_setup: bool, name: &'static str) -> Self {
+ fn screen_pairing_mode(initial_setup: bool, name: &'static str) -> (u32, u32) {
let mut screen = PairingModeScreen::new(name.into());
if !initial_setup {
screen = screen.with_screen_border(SCREEN_BORDER_BLUE);
}
- Self::PairingMode(screen)
+ run(&mut screen, true, false)
}
#[cfg(feature = "ble")]
- fn init_wireless_setup(name: &'static str) -> Self {
- let screen = WirelessSetupScreen::new(name.into());
- Self::WirelessSetup(screen)
+ fn screen_wireless_setup(name: &'static str) -> (u32, u32) {
+ let mut screen = WirelessSetupScreen::new(name.into());
+ run(&mut screen, true, true)
}
-}
-
-impl BootloaderUI for UIEckhart {
- type CLayoutType = BootloaderLayout;
fn screen_install_success(restart_seconds: u8, initial_setup: bool, complete_draw: bool) {
let header_color = if initial_setup { GREEN_LIGHT } else { GREY };
@@ -286,7 +236,8 @@ impl BootloaderUI for UIEckhart {
screen = screen.with_secondary_text(alert);
}
- run(&mut screen)
+ let (_, res) = run(&mut screen, true, false);
+ res
}
fn screen_wipe_confirm() -> u32 {
@@ -305,7 +256,8 @@ impl BootloaderUI for UIEckhart {
.with_action_bar(BldActionBar::new_double(left, right))
.with_screen_border(SCREEN_BORDER_RED);
- run(&mut screen)
+ let (_, res) = run(&mut screen, true, false);
+ res
}
fn screen_unlock_bootloader_confirm() -> u32 {
@@ -325,7 +277,8 @@ impl BootloaderUI for UIEckhart {
.with_action_bar(BldActionBar::new_double(left, right))
.with_screen_border(SCREEN_BORDER_RED);
- run(&mut screen)
+ let (_, res) = run(&mut screen, true, false);
+ res
}
fn screen_unlock_bootloader_success() {
@@ -340,7 +293,7 @@ impl BootloaderUI for UIEckhart {
))
.with_screen_border(SCREEN_BORDER_RED);
- run(&mut screen);
+ run(&mut screen, true, false);
}
fn screen_intro(bld_version: &str, vendor: &str, version: &str, fw_ok: bool) -> u32 {
@@ -371,7 +324,8 @@ impl BootloaderUI for UIEckhart {
);
}
- run(&mut screen)
+ let (_, res) = run(&mut screen, true, false);
+ res
}
fn screen_boot_stage_1(_fading: bool) {}
@@ -428,7 +382,7 @@ impl BootloaderUI for UIEckhart {
))
.with_screen_border(SCREEN_BORDER_RED);
- run(&mut screen);
+ run(&mut screen, true, false);
}
fn screen_wipe_fail() {
@@ -544,7 +498,8 @@ impl BootloaderUI for UIEckhart {
if !initial_setup {
screen = screen.with_screen_border(SCREEN_BORDER_BLUE);
}
- run(&mut screen)
+ let (_, res) = run(&mut screen, true, false);
+ res
}
#[cfg(feature = "ble")]
@@ -553,7 +508,8 @@ impl BootloaderUI for UIEckhart {
if !initial_setup {
screen = screen.with_screen_border(SCREEN_BORDER_BLUE);
}
- run(&mut screen)
+ let (_, res) = run(&mut screen, true, false);
+ res
}
#[cfg(feature = "power_manager")]
diff --git a/core/embed/rust/src/ui/ui_bootloader.rs b/core/embed/rust/src/ui/ui_bootloader.rs
index f8b8f1c9..b5bbdadd 100644
--- a/core/embed/rust/src/ui/ui_bootloader.rs
+++ b/core/embed/rust/src/ui/ui_bootloader.rs
@@ -1,24 +1,19 @@
-use crate::ui::component::Event;
+pub trait BootloaderUI {
+ fn screen_welcome() -> (u32, u32);
+
+ fn screen_menu(initial_setup: bool, communication: bool) -> (u32, u32);
-pub trait BootloaderLayoutType {
- fn event(&mut self, event: Option<Event>) -> u32;
+ fn screen_connect(initial_setup: bool, auto_update: bool) -> (u32, u32);
- fn render(&mut self) {
+ #[cfg(feature = "ble")]
+ fn screen_pairing_mode(_initial_setup: bool, _name: &'static str) -> (u32, u32) {
unimplemented!();
}
- fn show(&mut self) -> u32;
- fn init_welcome() -> Self;
- fn init_menu(initial_setup: bool) -> Self;
- fn init_connect(initial_setup: bool, auto_update: bool) -> Self;
- #[cfg(feature = "ble")]
- fn init_pairing_mode(initial_setup: bool, name: &'static str) -> Self;
#[cfg(feature = "ble")]
- fn init_wireless_setup(name: &'static str) -> Self;
-}
-
-pub trait BootloaderUI {
- type CLayoutType: BootloaderLayoutType;
+ fn screen_wireless_setup(_name: &'static str) -> (u32, u32) {
+ unimplemented!();
+ }
fn screen_install_success(restart_seconds: u8, initial_setup: bool, complete_draw: bool);
@@ -70,10 +65,14 @@ pub trait BootloaderUI {
);
#[cfg(feature = "ble")]
- fn screen_confirm_pairing(code: u32, initial_setup: bool) -> u32;
+ fn screen_confirm_pairing(_code: u32, _initial_setup: bool) -> u32 {
+ unimplemented!();
+ }
#[cfg(feature = "ble")]
- fn screen_pairing_mode_finalizing(initial_setup: bool) -> u32;
+ fn screen_pairing_mode_finalizing(_initial_setup: bool) -> u32 {
+ unimplemented!();
+ }
#[cfg(feature = "power_manager")]
fn screen_bootloader_entry_progress(_progress: u16, _initialize: bool) {
diff --git a/core/embed/rust/trezorhal.h b/core/embed/rust/trezorhal.h
index 6527e5c7..7605232f 100644
--- a/core/embed/rust/trezorhal.h
+++ b/core/embed/rust/trezorhal.h
@@ -55,6 +55,10 @@
#include <sec/storage.h>
#endif
+#ifdef BOOTLOADER
+#include "workflow/workflow_common.h"
+#endif
+
#include "bip39.h"
#include "rand.h"
#include "slip39.h"
Why this scored 28/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.