refactor(core/bootloader): simplify function headers by using one struct with all needed FW info
What changed, and why it matters
This commit is a straightforward code cleanup in the Trezor bootloader. It bundles three pieces of firmware information (vendor header, image header, and whether firmware is present) into a single struct and passes that struct around instead of three separate arguments. There is no change to security logic, no bug fix, and no new feature.
No security action needed. Treat as normal refactoring review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors bootloader workflow and protocol functions to accept a single fw_info_t pointer containing vhdr, hdr, and firmware_present, rather than passing those values as individual parameters. The struct is defined in protob.h and propagated through main.c, protob.c, and all workflow files. Behavior is preserved: the same null checks are performed (now on fw, fw->vhdr, and fw->hdr), and the same values are read from the same fields. Empty-device paths continue to pass NULL for the fw_info_t pointer, which the updated functions handle identically.
Changed components
core/embed/projects/bootloader/main.ccore/embed/projects/bootloader/protob/protob.ccore/embed/projects/bootloader/protob/protob.hcore/embed/projects/bootloader/workflow/wf_auto_update.ccore/embed/projects/bootloader/workflow/wf_ble_pairing_request.ccore/embed/projects/bootloader/workflow/wf_bootloader.ccore/embed/projects/bootloader/workflow/wf_empty_device.ccore/embed/projects/bootloader/workflow/wf_get_features.ccore/embed/projects/bootloader/workflow/wf_host_control.ccore/embed/projects/bootloader/workflow/wf_initialize.ccore/embed/projects/bootloader/workflow/workflow.hInspect captured patch +58 / −98
diff --git a/core/embed/projects/bootloader/main.c b/core/embed/projects/bootloader/main.c
index 24448d1a..33b1a998 100644
--- a/core/embed/projects/bootloader/main.c
+++ b/core/embed/projects/bootloader/main.c
@@ -710,10 +710,12 @@ int bootloader_main(void) {
#endif
if (header_present == sectrue) {
+ fw_info_t fw = {
+ .vhdr = &vhdr, .hdr = hdr, .firmware_present = firmware_present};
if (auto_upgrade == sectrue && firmware_present == sectrue) {
- result = workflow_auto_update(&vhdr, hdr, firmware_present);
+ result = workflow_auto_update(&fw);
} else {
- result = workflow_bootloader(&vhdr, hdr, firmware_present);
+ result = workflow_bootloader(&fw);
}
} else {
result = workflow_empty_device();
diff --git a/core/embed/projects/bootloader/protob/protob.c b/core/embed/projects/bootloader/protob/protob.c
index 86865821..5b11f121 100644
--- a/core/embed/projects/bootloader/protob/protob.c
+++ b/core/embed/projects/bootloader/protob/protob.c
@@ -105,9 +105,7 @@ secbool send_msg_success(protob_io_t *iface, const char *msg) {
return MSG_SEND(Success);
}
-secbool send_msg_features(protob_io_t *iface, const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present) {
+secbool send_msg_features(protob_io_t *iface, const fw_info_t *fw) {
MSG_SEND_INIT(Features);
MSG_SEND_ASSIGN_STRING(vendor, "trezor.io");
MSG_SEND_ASSIGN_REQUIRED_VALUE(major_version, VERSION_MAJOR);
@@ -116,13 +114,13 @@ secbool send_msg_features(protob_io_t *iface, const vendor_header *const vhdr,
MSG_SEND_ASSIGN_VALUE(bootloader_mode, true);
MSG_SEND_ASSIGN_STRING(model, MODEL_NAME);
MSG_SEND_ASSIGN_STRING(internal_model, MODEL_INTERNAL_NAME);
- if (vhdr && hdr) {
+ if (fw != NULL && fw->vhdr != NULL && fw->hdr != NULL) {
MSG_SEND_ASSIGN_VALUE(firmware_present, true);
- MSG_SEND_ASSIGN_VALUE(fw_major, (hdr->version & 0xFF));
- MSG_SEND_ASSIGN_VALUE(fw_minor, ((hdr->version >> 8) & 0xFF));
- MSG_SEND_ASSIGN_VALUE(fw_patch, ((hdr->version >> 16) & 0xFF));
- MSG_SEND_ASSIGN_STRING_LEN(fw_vendor, vhdr->vstr, vhdr->vstr_len);
- MSG_SEND_ASSIGN_VALUE(firmware_corrupted, sectrue != firmware_present);
+ MSG_SEND_ASSIGN_VALUE(fw_major, (fw->hdr->version & 0xFF));
+ MSG_SEND_ASSIGN_VALUE(fw_minor, ((fw->hdr->version >> 8) & 0xFF));
+ MSG_SEND_ASSIGN_VALUE(fw_patch, ((fw->hdr->version >> 16) & 0xFF));
+ MSG_SEND_ASSIGN_STRING_LEN(fw_vendor, fw->vhdr->vstr, fw->vhdr->vstr_len);
+ MSG_SEND_ASSIGN_VALUE(firmware_corrupted, sectrue != fw->firmware_present);
} else {
MSG_SEND_ASSIGN_VALUE(firmware_present, false);
MSG_SEND_ASSIGN_VALUE(firmware_corrupted, false);
diff --git a/core/embed/projects/bootloader/protob/protob.h b/core/embed/projects/bootloader/protob/protob.h
index 18663ccb..53535b5c 100644
--- a/core/embed/projects/bootloader/protob/protob.h
+++ b/core/embed/projects/bootloader/protob/protob.h
@@ -41,9 +41,13 @@ typedef struct {
secbool send_user_abort(protob_io_t *iface, const char *msg);
-secbool send_msg_features(protob_io_t *iface, const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present);
+typedef struct {
+ const vendor_header *vhdr;
+ const image_header *hdr;
+ secbool firmware_present;
+} fw_info_t;
+
+secbool send_msg_features(protob_io_t *iface, const fw_info_t *fw);
secbool send_msg_failure(protob_io_t *iface, FailureType type, const char *msg);
diff --git a/core/embed/projects/bootloader/workflow/wf_auto_update.c b/core/embed/projects/bootloader/workflow/wf_auto_update.c
index d5565448..247b65f0 100644
--- a/core/embed/projects/bootloader/workflow/wf_auto_update.c
+++ b/core/embed/projects/bootloader/workflow/wf_auto_update.c
@@ -29,9 +29,7 @@
#include "wire/wire_iface_usb.h"
#include "workflow.h"
-workflow_result_t workflow_auto_update(const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present) {
+workflow_result_t workflow_auto_update(const fw_info_t *fw) {
ui_set_initial_setup(true);
workflow_result_t res = WF_CANCELLED;
@@ -45,8 +43,7 @@ workflow_result_t workflow_auto_update(const vendor_header *const vhdr,
c_layout_t layout;
memset(&layout, 0, sizeof(layout));
screen_connect(true, false, &layout);
- res = workflow_host_control(vhdr, hdr, firmware_present, &layout, &ui_result,
- &ios);
+ res = workflow_host_control(fw, &layout, &ui_result, &ios);
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 aee81c0a..b6c7b00d 100644
--- a/core/embed/projects/bootloader/workflow/wf_ble_pairing_request.c
+++ b/core/embed/projects/bootloader/workflow/wf_ble_pairing_request.c
@@ -44,9 +44,7 @@ static bool encode_pairing_code(uint32_t code, uint8_t *outbuf) {
return true;
}
-workflow_result_t workflow_ble_pairing_request(const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present) {
+workflow_result_t workflow_ble_pairing_request(const fw_info_t *fw) {
if (!ble_iface_start_pairing()) {
return WF_OK_PAIRING_FAILED;
}
@@ -63,8 +61,7 @@ workflow_result_t workflow_ble_pairing_request(const vendor_header *const vhdr,
screen_pairing_mode(ui_get_initial_setup(), name, strlen(name), &layout);
uint32_t code = 0;
- workflow_result_t res =
- workflow_host_control(vhdr, hdr, firmware_present, &layout, &code, NULL);
+ workflow_result_t res = workflow_host_control(fw, &layout, &code, NULL);
#ifdef USE_RGB_LED
rgb_led_effect_stop();
@@ -132,9 +129,7 @@ workflow_result_t workflow_ble_pairing_request(const vendor_header *const vhdr,
return WF_OK_PAIRING_COMPLETED;
}
-workflow_result_t workflow_wireless_setup(const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present,
+workflow_result_t workflow_wireless_setup(const fw_info_t *fw,
protob_ios_t *ios) {
if (!ble_iface_start_pairing()) {
return WF_OK_PAIRING_FAILED;
@@ -152,8 +147,7 @@ workflow_result_t workflow_wireless_setup(const vendor_header *const vhdr,
screen_wireless_setup(name, strlen(name), &layout);
uint32_t code = 0;
- workflow_result_t res =
- workflow_host_control(vhdr, hdr, firmware_present, &layout, &code, ios);
+ workflow_result_t res = workflow_host_control(fw, &layout, &code, ios);
#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 fb232c51..38e08404 100644
--- a/core/embed/projects/bootloader/workflow/wf_bootloader.c
+++ b/core/embed/projects/bootloader/workflow/wf_bootloader.c
@@ -39,16 +39,14 @@
#include "rust_ui_bootloader.h"
#include "workflow.h"
-workflow_result_t workflow_menu(const vendor_header* const vhdr,
- const image_header* const hdr,
- secbool firmware_present, protob_ios_t* ios) {
+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(
- vhdr, hdr, firmware_present, &layout, &ui_result, ios);
+ workflow_result_t result =
+ workflow_host_control(fw, &layout, &ui_result, ios);
if (result != WF_OK_UI_ACTION) {
return result;
@@ -62,7 +60,7 @@ workflow_result_t workflow_menu(const vendor_header* const vhdr,
#ifdef USE_BLE
if (menu_result == MENU_BLUETOOTH) {
workflow_ifaces_pause(ios);
- workflow_ble_pairing_request(vhdr, hdr, firmware_present);
+ workflow_ble_pairing_request(fw);
workflow_ifaces_resume(ios);
if (ios == NULL) {
// in case we were not in connected-mode, stop advertising
@@ -107,10 +105,9 @@ typedef enum {
// Each handler returns either a next screen, or SCREEN_DONE and an out‑param
// for the result.
-static screen_t handle_intro(const vendor_header* vhdr, const image_header* hdr,
- secbool firmware_present,
+static screen_t handle_intro(const fw_info_t* fw,
workflow_result_t* out_result) {
- intro_result_t ui = ui_screen_intro(vhdr, hdr, firmware_present);
+ intro_result_t ui = ui_screen_intro(fw->vhdr, fw->hdr, fw->firmware_present);
if (ui == INTRO_MENU) return SCREEN_MENU;
if (ui == INTRO_HOST) return SCREEN_WAIT_FOR_HOST;
// no other valid INTRO result -> fatal
@@ -118,10 +115,9 @@ static screen_t handle_intro(const vendor_header* vhdr, const image_header* hdr,
return SCREEN_DONE;
}
-static screen_t handle_menu(const vendor_header* vhdr, const image_header* hdr,
- secbool firmware_present,
+static screen_t handle_menu(const fw_info_t* fw,
workflow_result_t* out_result) {
- workflow_result_t res = workflow_menu(vhdr, hdr, firmware_present, NULL);
+ workflow_result_t res = workflow_menu(fw, NULL);
switch (res) {
case WF_OK:
return SCREEN_INTRO; // back to intro
@@ -133,9 +129,7 @@ static screen_t handle_menu(const vendor_header* vhdr, const image_header* hdr,
}
}
-static screen_t handle_wait_for_host(const vendor_header* vhdr,
- const image_header* hdr,
- secbool firmware_present,
+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));
@@ -150,8 +144,7 @@ static screen_t handle_wait_for_host(const vendor_header* vhdr,
while (next_screen == SCREEN_WAIT_FOR_HOST) {
screen_connect(false, true, &layout);
- workflow_result_t res = workflow_host_control(vhdr, hdr, firmware_present,
- &layout, &ui_res, &ios);
+ workflow_result_t res = workflow_host_control(fw, &layout, &ui_res, &ios);
switch (res) {
case WF_OK_UI_ACTION: {
@@ -162,8 +155,7 @@ static screen_t handle_wait_for_host(const vendor_header* vhdr,
#ifdef USE_BLE
case CONNECT_PAIRING_MODE: {
workflow_ifaces_pause(&ios);
- workflow_result_t ble =
- workflow_ble_pairing_request(vhdr, hdr, firmware_present);
+ workflow_result_t ble = workflow_ble_pairing_request(fw);
workflow_ifaces_resume(&ios);
if (ble == WF_OK_PAIRING_COMPLETED || ble == WF_OK_PAIRING_FAILED) {
next_screen = SCREEN_WAIT_FOR_HOST;
@@ -179,7 +171,7 @@ static screen_t handle_wait_for_host(const vendor_header* vhdr,
case CONNECT_MENU: {
workflow_result_t menu_result = WF_CANCELLED;
while (menu_result == WF_CANCELLED) {
- menu_result = workflow_menu(vhdr, hdr, firmware_present, &ios);
+ menu_result = workflow_menu(fw, &ios);
switch (menu_result) {
case WF_OK:
next_screen = SCREEN_WAIT_FOR_HOST;
@@ -217,9 +209,7 @@ static screen_t handle_wait_for_host(const vendor_header* vhdr,
return next_screen;
}
-workflow_result_t workflow_bootloader(const vendor_header* vhdr,
- const image_header* hdr,
- secbool firmware_present) {
+workflow_result_t workflow_bootloader(const fw_info_t* fw) {
ui_set_initial_setup(false);
screen_t screen = SCREEN_INTRO;
workflow_result_t final_res = WF_ERROR_FATAL;
@@ -227,13 +217,13 @@ workflow_result_t workflow_bootloader(const vendor_header* vhdr,
while (screen != SCREEN_DONE) {
switch (screen) {
case SCREEN_INTRO:
- screen = handle_intro(vhdr, hdr, firmware_present, &final_res);
+ screen = handle_intro(fw, &final_res);
break;
case SCREEN_MENU:
- screen = handle_menu(vhdr, hdr, firmware_present, &final_res);
+ screen = handle_menu(fw, &final_res);
break;
case SCREEN_WAIT_FOR_HOST:
- screen = handle_wait_for_host(vhdr, hdr, firmware_present, &final_res);
+ screen = handle_wait_for_host(fw, &final_res);
break;
default:
// shouldn’t happen
diff --git a/core/embed/projects/bootloader/workflow/wf_empty_device.c b/core/embed/projects/bootloader/workflow/wf_empty_device.c
index 09761a0f..21d8f41c 100644
--- a/core/embed/projects/bootloader/workflow/wf_empty_device.c
+++ b/core/embed/projects/bootloader/workflow/wf_empty_device.c
@@ -76,11 +76,10 @@ workflow_result_t workflow_empty_device(void) {
c_layout_t layout;
memset(&layout, 0, sizeof(layout));
screen_welcome(&layout);
- res =
- workflow_host_control(NULL, NULL, secfalse, &layout, &ui_result, &ios);
+ res = workflow_host_control(NULL, &layout, &ui_result, &ios);
#ifdef USE_BLE
if (res == WF_OK_UI_ACTION && ui_result == WELCOME_PAIRING_MODE) {
- res = workflow_wireless_setup(NULL, NULL, secfalse, &ios);
+ res = workflow_wireless_setup(NULL, &ios);
if (res == WF_OK_PAIRING_COMPLETED || res == WF_OK_PAIRING_FAILED) {
res = WF_CANCELLED;
ui_result = WELCOME_CANCEL;
@@ -91,7 +90,7 @@ workflow_result_t workflow_empty_device(void) {
#endif
if (res == WF_OK_UI_ACTION && ui_result == WELCOME_MENU) {
do {
- res = workflow_menu(NULL, NULL, secfalse, &ios);
+ res = workflow_menu(NULL, &ios);
} while (res == WF_CANCELLED);
if (res == WF_OK) {
diff --git a/core/embed/projects/bootloader/workflow/wf_get_features.c b/core/embed/projects/bootloader/workflow/wf_get_features.c
index f25ec5db..da893e46 100644
--- a/core/embed/projects/bootloader/workflow/wf_get_features.c
+++ b/core/embed/projects/bootloader/workflow/wf_get_features.c
@@ -24,11 +24,9 @@
#include "workflow.h"
workflow_result_t workflow_get_features(protob_io_t *iface,
- const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present) {
+ const fw_info_t *fw) {
GetFeatures msg_recv;
recv_msg_get_features(iface, &msg_recv);
- send_msg_features(iface, vhdr, hdr, firmware_present);
+ send_msg_features(iface, fw);
return WF_OK;
}
diff --git a/core/embed/projects/bootloader/workflow/wf_host_control.c b/core/embed/projects/bootloader/workflow/wf_host_control.c
index 66098cf9..38553815 100644
--- a/core/embed/projects/bootloader/workflow/wf_host_control.c
+++ b/core/embed/projects/bootloader/workflow/wf_host_control.c
@@ -53,9 +53,7 @@
#endif
-workflow_result_t workflow_host_control(const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present,
+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) {
@@ -229,7 +227,7 @@ workflow_result_t workflow_host_control(const vendor_header *const vhdr,
switch (msg_id) {
case MessageType_MessageType_Initialize:
- workflow_initialize(active_iface, vhdr, hdr, firmware_present);
+ workflow_initialize(active_iface, fw);
// whatever the result, we stay here and continue
break;
case MessageType_MessageType_Ping:
@@ -237,7 +235,7 @@ workflow_result_t workflow_host_control(const vendor_header *const vhdr,
// whatever the result, we stay here and continue
break;
case MessageType_MessageType_GetFeatures:
- workflow_get_features(active_iface, vhdr, hdr, firmware_present);
+ workflow_get_features(active_iface, fw);
// whatever the result, we stay here and continue
break;
case MessageType_MessageType_WipeDevice:
diff --git a/core/embed/projects/bootloader/workflow/wf_initialize.c b/core/embed/projects/bootloader/workflow/wf_initialize.c
index 45a3bfe4..66c34133 100644
--- a/core/embed/projects/bootloader/workflow/wf_initialize.c
+++ b/core/embed/projects/bootloader/workflow/wf_initialize.c
@@ -23,12 +23,9 @@
#include "protob.h"
#include "workflow.h"
-workflow_result_t workflow_initialize(protob_io_t *iface,
- const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present) {
+workflow_result_t workflow_initialize(protob_io_t *iface, const fw_info_t *fw) {
Initialize msg_recv;
recv_msg_initialize(iface, &msg_recv);
- send_msg_features(iface, vhdr, hdr, firmware_present);
+ send_msg_features(iface, fw);
return WF_OK;
}
diff --git a/core/embed/projects/bootloader/workflow/workflow.h b/core/embed/projects/bootloader/workflow/workflow.h
index 65d28f38..cf833caf 100644
--- a/core/embed/projects/bootloader/workflow/workflow.h
+++ b/core/embed/projects/bootloader/workflow/workflow.h
@@ -51,45 +51,28 @@ workflow_result_t workflow_unlock_bootloader(protob_io_t *iface);
workflow_result_t workflow_ping(protob_io_t *iface);
-workflow_result_t workflow_initialize(protob_io_t *iface,
- const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present);
+workflow_result_t workflow_initialize(protob_io_t *iface, const fw_info_t *fw);
workflow_result_t workflow_get_features(protob_io_t *iface,
- const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present);
+ const fw_info_t *fw);
-workflow_result_t workflow_menu(const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present, protob_ios_t *ios);
+workflow_result_t workflow_menu(const fw_info_t *fw, protob_ios_t *ios);
-workflow_result_t workflow_bootloader(const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present);
+workflow_result_t workflow_bootloader(const fw_info_t *fw);
workflow_result_t workflow_empty_device(void);
-workflow_result_t workflow_host_control(const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present,
+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 vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present);
+workflow_result_t workflow_auto_update(const fw_info_t *fw);
#ifdef USE_BLE
-workflow_result_t workflow_ble_pairing_request(const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present);
+workflow_result_t workflow_ble_pairing_request(const fw_info_t *fw);
-workflow_result_t workflow_wireless_setup(const vendor_header *const vhdr,
- const image_header *const hdr,
- secbool firmware_present,
+workflow_result_t workflow_wireless_setup(const fw_info_t *fw,
protob_ios_t *ios);
#endif
Why this scored 15/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.