Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bootloader refactoring #4572

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

bootloader refactoring #4572

wants to merge 5 commits into from

Conversation

TychoVrahe
Copy link
Contributor

@TychoVrahe TychoVrahe commented Feb 4, 2025

This PR implements major bootloader refactoring - as preparation for adding BLE.

  • overall structure should be close to how things are done in firmware/micropython
  • cleaner separation of communication layers
  • introducing workflows, separate of communication
  • workflows run from menu use same code as workflows triggered by communication
  • introducing unified polling mechanism
  • some error handling in communication is improved/introduced

@TychoVrahe TychoVrahe self-assigned this Feb 4, 2025
Copy link

github-actions bot commented Feb 4, 2025

core UI changes device test click test persistence test
T2T1 Model T test(screens) main(screens) test(screens) main(screens) test(screens) main(screens)
T3B1 Safe 3 test(screens) main(screens) test(screens) main(screens) test(screens) main(screens)
T3T1 Safe 5 test(screens) main(screens) test(screens) main(screens) test(screens) main(screens)
All main(screens)

@TychoVrahe TychoVrahe force-pushed the tychovrahe/bootloader/reorg branch 5 times, most recently from bedf3bb to 97363e2 Compare February 6, 2025 15:14
@TychoVrahe TychoVrahe force-pushed the tychovrahe/bootloader/reorg branch from f37dfa0 to 8e4557e Compare February 7, 2025 20:51
@TychoVrahe TychoVrahe marked this pull request as ready for review February 9, 2025 20:56
@TychoVrahe TychoVrahe requested a review from prusnak as a code owner February 9, 2025 20:56
@TychoVrahe TychoVrahe requested review from matejcik, hiviah and cepetr and removed request for prusnak February 9, 2025 20:56
Copy link
Contributor

@hiviah hiviah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nicer without the hardcoded ui_result constants in workflow_bootloader, but they were there before he refactor.

@@ -64,27 +57,16 @@
#include <sec/hash_processor.h>
#endif

#include <io/usb.h>
#include "version.h"
#include <workflow/workflow.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be included as "workflow/worfklow.h", since it's inside the bootloader folder

UI_RESULT_CANCEL = 1,
UI_RESULT_CONFIRM = 2,
} ui_result_t;

typedef enum {
SCREEN_INTRO = 0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enum describes the states of the workflow in wf_bootloader.c and might belong in this file. Some of the enum entries are unused.

const image_header *const hdr) {
workflow_reset_jump();
ui_set_initial_setup(true);
ui_screen_connect();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we called redraw_screen_wait() at the beginning of workflow_host_control(), we would not need to call ui_screen_connect() here. The same applies to workflow_bootloader and workflow_empty_device.


workflow_result_t workflow_auto_update(const vendor_header *const vhdr,
const image_header *const hdr) {
workflow_reset_jump();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be better/safer to call workflow_reset_jump() outside this function - in the loop in main, just after do {…. Then we can remove this call from workflow_bootloader and workflow_empty_device as well.


#include "workflow.h"

void workflow_allow_jump_1(void);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These names are a bit confusing to me since the logic inside isn’t a workflow.

poll_event_t* event, uint32_t timeout_ms) {
uint32_t start = systick_ms();

while (systick_ms() - start < timeout_ms) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using the pattern below? It inherently solves the uint32 overflow problem.

uint32_t deadline = ticks_timeout(timeout_ms);

while (! ticks_expired(deadline)) {
...

..

ensure(dont_optimize_out_true * (workflow_is_jump_allowed_1() ==
workflow_is_jump_allowed_2()),
NULL);
#ifdef USE_RESET_TO_BOOT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we don’t need to set firmware_jump_fn here, as it is set a bit later, right after the switch statement.

firmware_jump_fn = real_jump_to_firmware;
#endif
break;
return 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of returning here, shouldn’t we call eboot_or_halt_after_rsod() or shutdown_error() ? I think this return will result in showing the RSOD with the “EXIT 1” text.

WF_SHUTDOWN = 0x11223344,
WF_CONTINUE_TO_FIRMWARE = 0xAABBCCDD,
WF_RETURN = 0x55667788,
WF_STAY = 0xEEFF0011,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The meaning of the result constants is a bit unclear to me. It would feel more natural to have results that describe what happened in that workflow, allowing the caller to decide what to do. For example:

  • WF_ERROR- Shutdown without overwriting the display.
  • WF_FATAL_ERROR - Show a fatal error message, then shut down.
  • WF_OK - Workflow successfully finished (can replace WF_RETURN and WF_CONTINUE_TO_FIRMWARE).

}
} while (result == WF_STAY || result == WF_RETURN);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that the do…while loop here is unnecessary since it is already incorporated into all workflows it calls. These workflows never return WF_STAY nor WF_RETURN.

break;
case SCREEN_MENU:
ui_result = ui_screen_menu(firmware_present);
if (ui_result == 0xAABBCCDD) { // exit menu
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These constants (0xAABBCCDD...) are the same as the workflow_result_t constants, which feels a bit strange. Shouldn’t we use WF_xxx here instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 🏃‍♀️ In progress
Development

Successfully merging this pull request may close these issues.

3 participants