From c8b444cefc353a94d72aa3de29acf6b22914eea9 Mon Sep 17 00:00:00 2001 From: Ellis Sarza-Nguyen Date: Wed, 17 Dec 2025 10:32:28 -0800 Subject: [PATCH] [examples] Modify DFU update to add skip logic 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 --- examples/htool_dfu.c | 88 ++++++++++++++++++++++++++++++------ examples/htool_dfu.h | 2 + protocol/opentitan_version.c | 60 ++++++++++++++++++++++++ protocol/opentitan_version.h | 17 +++++++ 4 files changed, 153 insertions(+), 14 deletions(-) diff --git a/examples/htool_dfu.c b/examples/htool_dfu.c index cf50ed8..caf0fd2 100644 --- a/examples/htool_dfu.c +++ b/examples/htool_dfu.c @@ -14,6 +14,7 @@ #include "htool.h" #include "htool_cmd.h" #include "protocol/dfu_hostcmd.h" +#include "protocol/opentitan_version.h" int htool_dfu_update(const struct htool_invocation* inv) { struct libhoth_device* dev = htool_libhoth_device(); @@ -21,6 +22,10 @@ int htool_dfu_update(const struct htool_invocation* inv) { return -1; } + struct opentitan_image_version desired_rom_ext = {0}; + struct opentitan_image_version desired_app = {0}; + struct opentitan_get_version_resp resp = {0}; + uint32_t complete_flags = 0; const char* reset_arg; if (htool_get_param_string(inv, "reset", &reset_arg)) { @@ -68,25 +73,80 @@ int htool_dfu_update(const struct htool_invocation* inv) { if (image == MAP_FAILED) { fprintf(stderr, "mmap error: %s\n", strerror(errno)); goto cleanup; + } + + // Populate rom_ext and app with the desired extracted versions from the image + retval = libhoth_extract_ot_bundle(image, &desired_rom_ext, &desired_app); + + if(retval != 0) { + fprintf(stderr, "Failed to extract bundle\n"); + goto cleanup2; } - if (libhoth_dfu_update(dev, image, statbuf.st_size, complete_flags) != 0) { - fprintf(stderr, "DFU update failed.\n"); + // Get the current version of the device + retval = libhoth_opentitan_version(dev, &resp); + + if(retval != 0) { + fprintf(stderr, "Failed to get current version\n"); goto cleanup2; } - retval = 0; + + // Determine the stage slot for each ot get version to compare + uint32_t rom_ext_boot_slot = bootslot_int(resp.rom_ext.booted_slot); + uint32_t rom_ext_stage_slot = rom_ext_boot_slot == 0 ? 1 : 0; + uint32_t app_boot_slot = bootslot_int(resp.app.booted_slot); + uint32_t app_stage_slot = app_boot_slot == 0 ? 1 : 0; + + // Compare the desired version with the current bootslot version + // If they are different, we need to automatically perform the x2 update + // If both are the same & the staged slot is different, we need to perform a single update + // For all other cases, no update is needed + if(libhoth_ot_version_eq(&resp.rom_ext.slots[rom_ext_boot_slot], &desired_rom_ext) == false || + libhoth_ot_version_eq(&resp.app.slots[app_boot_slot], &desired_app) == false ) { + printf("The current bootslot is not the desired version. Performing DFU update x2...\n"); + // Peform the DFU update twice to update both slots + // First update will stage to the non-booted slot, second update correct the newly staged slot. + for(int i = 0; i < 2; i++){ + retval = libhoth_dfu_update( + dev, image, statbuf.st_size, complete_flags); + + if(retval != 0) { + fprintf(stderr, "DFU update failed\n"); + goto cleanup2; + } + } + } + else{ + if(libhoth_ot_version_eq(&resp.rom_ext.slots[rom_ext_stage_slot], &desired_rom_ext) == false || + libhoth_ot_version_eq(&resp.app.slots[app_stage_slot], &desired_app) == false ) { + printf("The staged slot is not the desired version. Performing DFU update x1...\n"); + // Perform a single DFU update to update the staged slot + retval = libhoth_dfu_update( + dev, image, statbuf.st_size, complete_flags); + + if(retval != 0) { + fprintf(stderr, "DFU update failed\n"); + goto cleanup2; + } + } + else{ + printf("Device is already at the desired version. No DFU update needed.\n"); + } + } int ret; -cleanup2: - ret = munmap(image, statbuf.st_size); - if (ret != 0) { - fprintf(stderr, "munmap error: %d\n", ret); - } -cleanup: - ret = close(fd); - if (ret != 0) { - fprintf(stderr, "close error: %d\n", ret); - } + cleanup2: + ret = munmap(image, statbuf.st_size); + if (ret != 0) { + fprintf(stderr, "munmap error: %d\n", ret); + } + + cleanup: + ret = close(fd); + if (ret != 0) { + fprintf(stderr, "close error: %d\n", ret); + } + return retval; -} +} \ No newline at end of file diff --git a/examples/htool_dfu.h b/examples/htool_dfu.h index 12835d6..39cc0d0 100644 --- a/examples/htool_dfu.h +++ b/examples/htool_dfu.h @@ -15,6 +15,8 @@ #ifndef LIBHOTH_EXAMPLES_HTOOL_DFU_H_ #define LIBHOTH_EXAMPLES_HTOOL_DFU_H_ +#include "protocol/opentitan_version.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/protocol/opentitan_version.c b/protocol/opentitan_version.c index 7504a64..d953edb 100644 --- a/protocol/opentitan_version.c +++ b/protocol/opentitan_version.c @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include "opentitan_version.h" @@ -32,6 +33,51 @@ int libhoth_opentitan_version(struct libhoth_device * dev, return rv; } +int libhoth_extract_ot_bundle(const uint8_t* image, + struct opentitan_image_version * rom_ext, + struct opentitan_image_version * app) { + + // Check if the image is valid + if(image == NULL) { + fprintf(stderr, "Image is NULL\n"); + return -1; + } + + // Check if the image has the correct magic number + char magic[] = "_OTFWUPDATE_"; + for(int i = 0; i < (sizeof(magic) - 1); i++) { + if(image[i] != magic[i]) { + fprintf(stderr, "Image does not have the correct magic number\n"); + return -1; + } + } + + // Extract the offset that contains the ROM_EXT version information + // We will have the desired ROM_EXT version be stored on slot index 0 and keep slot index 1 with 0xDEADBEEF + uint32_t offset = (image[OPENTITAN_OFFSET_HEADER_DATA] | image[OPENTITAN_OFFSET_HEADER_DATA + 1] << 8 | image[OPENTITAN_OFFSET_HEADER_DATA + 2] << 16 | image[OPENTITAN_OFFSET_HEADER_DATA + 3] << 24); + rom_ext->major = image[offset + OPENTITAN_OFFSET_VERSION_MAJOR] | image[offset + OPENTITAN_OFFSET_VERSION_MAJOR + 1] << 8 | image[offset + OPENTITAN_OFFSET_VERSION_MAJOR + 2] << 16 | image[offset + OPENTITAN_OFFSET_VERSION_MAJOR + 3] << 24; + rom_ext->minor = image[offset + OPENTITAN_OFFSET_VERSION_MINOR] | image[offset + OPENTITAN_OFFSET_VERSION_MINOR + 1] << 8 | image[offset + OPENTITAN_OFFSET_VERSION_MINOR + 2] << 16 | image[offset + OPENTITAN_OFFSET_VERSION_MINOR + 3] << 24; + + // 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 + OPENTITAN_OFFSET_APP_FW; + app->major = image[offset_app + OPENTITAN_OFFSET_VERSION_MAJOR] | image[offset_app + OPENTITAN_OFFSET_VERSION_MAJOR + 1] << 8 | image[offset_app + OPENTITAN_OFFSET_VERSION_MAJOR + 2] << 16 | image[offset_app + OPENTITAN_OFFSET_VERSION_MAJOR + 3] << 24; + 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; + + return 0; +} + +bool libhoth_ot_version_eq(const struct opentitan_image_version * a, + const struct opentitan_image_version * b) { + + if(a->major == b->major && a->minor == b->minor) { + return true; + } else { + return false; + } + +} + char * bootslot_str(enum opentitan_boot_slot input) { // Primary BL0 slot values are hardcoded in pie_rot @@ -44,5 +90,19 @@ char * bootslot_str(enum opentitan_boot_slot input) { } else { return "Unknown boot slot"; } +} + +int bootslot_int(enum opentitan_boot_slot input) { + + // Primary BL0 slot values are hardcoded in pie_rot + // Boot slotA: 0x5f5f4141 + // Boot slotB: 0x42425f5f) + if (input == kOpentitanBootSlotA) { + return 0x0; + } else if (input == kOpentitanBootSlotB) { + return 0x1; + } else { + return 0x0; + } } \ No newline at end of file diff --git a/protocol/opentitan_version.h b/protocol/opentitan_version.h index cfa5213..f7fe4d0 100644 --- a/protocol/opentitan_version.h +++ b/protocol/opentitan_version.h @@ -17,6 +17,7 @@ #include #include +#include #include "host_cmd.h" #include "transports/libhoth_device.h" @@ -30,6 +31,13 @@ extern "C" { #define OPENTITAN_VERSION_HASH_SIZE 8 #define OPENTITAN_NUM_SLOTS 2 +#define OPENTITAN_OFFSET_HEADER_DATA 36 +#define OPENTITAN_OFFSET_APP_FW 65536 +#define OPENTITAN_OFFSET_VERSION_MAJOR 836 +#define OPENTITAN_OFFSET_VERSION_MINOR 840 +#define OPENTITAN_OFFSET_VERSION_SECURITY 844 +#define OPENTITAN_OFFSET_TIMESTAMP 848 + typedef uint32_t opentitan_boot_slot_t; enum opentitan_boot_slot { @@ -91,8 +99,17 @@ static_assert(sizeof(struct opentitan_get_version_resp) == 344, ""); int libhoth_opentitan_version(struct libhoth_device *device, struct opentitan_get_version_resp *response); +int libhoth_extract_ot_bundle(const uint8_t* image, + struct opentitan_image_version * rom_ext, + struct opentitan_image_version * app); + +bool libhoth_ot_version_eq(const struct opentitan_image_version * a, + const struct opentitan_image_version * b); + char *bootslot_str(enum opentitan_boot_slot input); +int bootslot_int(enum opentitan_boot_slot input); + #ifdef __cplusplus } #endif