-
-
Notifications
You must be signed in to change notification settings - Fork 677
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
base: main
Are you sure you want to change the base?
bootloader refactoring #4572
Conversation
|
bedf3bb
to
97363e2
Compare
[no changelog]
[no changelog]
[no changelog]
f37dfa0
to
8e4557e
Compare
There was a problem hiding this 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> |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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 replaceWF_RETURN
andWF_CONTINUE_TO_FIRMWARE
).
} | ||
} while (result == WF_STAY || result == WF_RETURN); |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
secbool send_msg_request_firmware(protob_iface_t *iface, uint32_t offset, | ||
uint32_t length) { | ||
if (iface == NULL) { | ||
return sectrue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The recv_msg_xxx()
functions return secfalse
if iface == NULL
, while the send_msg_xxx()
function returns sectrue
for the same condition. Shouldn’t we unify this?
// read function pointer | ||
int (*read)(uint8_t *buffer, size_t buffer_size); | ||
|
||
void (*error)(void); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like the error handler is called by the codec in the event of a fatal communication error. Shouldn’t the codec signal the error to a higher level instead? It seems to me that the error handler is compensating for something missing between the codec and the state machines above.
|
||
typedef struct { | ||
uint8_t iface_num; | ||
size_t tx_len; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to add comments explaining the purpose of these fields. Wouldn’t tx_packet_size
and rx_packet_size
be better names?
|
||
#include "codec_v1.h" | ||
|
||
void usb_iface_init(wire_iface_t* iface, secbool no_fw); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no_fw
is a bit confusing for me. Would be usb21_landing
a better name?
iface->error = &usb_error; | ||
} | ||
|
||
void usb_iface_deinit(wire_iface_t* iface) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
usb_iface_deinit()
is not called, nor is it in the header file. I think it was meant to be called instead of usb_deinit()
in wf_host_control.c
, wasn’t it?
This PR implements major bootloader refactoring - as preparation for adding BLE.