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