Skip to content

Conversation

@esnguyen
Copy link
Collaborator

No description provided.

@esnguyen esnguyen force-pushed the esnguyen/add_dfu_skip_logic branch 2 times, most recently from 75d8434 to d2de66b Compare December 22, 2025 17:22
#include "protocol/dfu_hostcmd.h"
#include "protocol/opentitan_version.h"

void process_image(struct libhoth_device* dev, const uint8_t* image, struct opentitan_image_version* rom_ext, struct opentitan_image_version* app, struct opentitan_get_version_resp * resp ) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it might be best to separate the processing of the file from fetching the version from the device. This way we can re-use it for other htool commands that just want to inspect the contents of a file.

Maybe rename this to something like: libhoth_extract_ot_bundle and move it into libhoth/protocol.

app->minor = image[offset_app + OPENTITAN_OFFSET_VERSION_MINOR] | image[offset_app + OPENTITAN_OFFSET_VERSION_MINOR + 1] << 8 | image[offset_app + OPENTITAN_OFFSET_VERSION_MINOR + 2] << 16 | image[offset_app + OPENTITAN_OFFSET_VERSION_MINOR + 3] << 24;

// Get the current version of the device
libhoth_opentitan_version(dev, resp);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you're dropping potential errors here.

// Process the current boot slot
uint32_t boot_slot = resp.primary_bl0_slot == kOpentitanBootSlotA ? 0 : 1;

if(resp.rom_ext.slots[boot_slot].major != rom_ext.major || resp.rom_ext.slots[boot_slot].minor != rom_ext.minor || resp.app.slots[boot_slot].major != app.major || resp.app.slots[boot_slot].minor != app.minor) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Turn some of this conditional into a helper function, libhoth_ot_version_eq, that just compares opentitan_image_version for equality.

fprintf(stderr, "DFU update failed.\n");
goto cleanup2;
// Process the current boot slot
uint32_t boot_slot = resp.primary_bl0_slot == kOpentitanBootSlotA ? 0 : 1;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the logic that we want is to compare both boot slots and do what is necessary for both boot slots to be this new version.

If both boot slots match this new image, do nothing. If only the current boot slot already has the image, just update once. Otherwise, perform the dfu_update twice.

}
}
else {
printf("Version match\n");
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should probably make the messages here a little more informative. Something like:
"Image version {version} already matches running OT version, skipping DFU update..."

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@stevenportley My logic has changed so I am not printing a msg. let me know if this message is still desired.

}
else {
printf("Version match\n");
return 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

We don't want to exit immediately because we still need to run some of the cleanup logic for unmapping the file.

if (ret != 0) {
fprintf(stderr, "close error: %d\n", ret);
}
goto cleanup2;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think you need these gotos

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will revisit this if needed. Logic change so please review this again if this is needed

For htools dfu, we seek to add some type of logic to skip an update.
With the opentitan get version, we can compare the versions and make the
decision to proceed or return with no actions.

Signed-off-by: Ellis Sarza-Nguyen <sarzanguyen@google.com>
@esnguyen esnguyen force-pushed the esnguyen/add_dfu_skip_logic branch from d2de66b to ca07f28 Compare December 23, 2025 18:15

// Extract the offset that contains the APP version information
// We will have the desired APP version be stored on slot index 0 and keep slot index 1 empty
uint32_t offset_app = offset + 65536;
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should name this constant

return 0;
}

int libhoth_ot_version_eq(const struct opentitan_get_version_resp * a,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this should look more like:

int libhoth_ot_version_eq(const struct opentitan_image_version* a, const struct opentitan_image_version* b)

and just do the major / minor comparison

return rv;
}

int libhoth_extract_ot_bundle(const uint8_t* image,
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can't really extra the bundle file into an struct opentitan_get_version_resp, because they're logically different things:

The fwupdate bundle contains a ROM_EXT and APP firmware.
The struct opentitan_get_version_resp contains information about the state of the OT chip, what it booted, and some metadata (preferred boot slot, owner_config, etc.).

As a result, you have to stub a bunch of extra data here with default/invalid values and check for them in other places. I think it would make more sense to have something like:

int libhoth_extract_ot_bundle(const uint8_t* image, struct opentitan_image_version* rom_ext, struct opentitan_image_version* app_fw)

and then you don't need the stubs and the other checks for 0xDEADBEEF

goto cleanup2;
int boot_count = 0;
uint32_t current_slot = bootslot_int(resp.primary_bl0_slot);
uint32_t next_slot = (current_slot == 0) ? 1 : 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

One subtlety here is that if we are currently booting the correct FW but the staging side is wrong, we only need to update once to fix the staging side.

However, if the staging side is correct but the currently running firmware is wrong, we still need to dfu update twice. The first will get us to boot into the other side, and the second will do that actual update.

fprintf(stderr, "DFU update failed.\n");
goto cleanup2;
int boot_count = 0;
uint32_t current_slot = bootslot_int(resp.primary_bl0_slot);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think what you're looking for here is actually booted_slot in opentitan_image_boot_info

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants