From db805e71db8f42703216e03de270194da73efb4b Mon Sep 17 00:00:00 2001 From: Steven Portley Date: Mon, 3 Aug 2026 15:03:21 -0700 Subject: [PATCH] dfu_hostcmd: Move dfu install to protocol/ This moves the rest of the DFU update procedure into protocol/ so that it is usable outside of htool. --- examples/htool_dfu.c | 144 +++++++---------------------------------- protocol/BUILD | 2 + protocol/dfu_hostcmd.c | 124 +++++++++++++++++++++++++++++++++++ protocol/dfu_hostcmd.h | 18 ++++++ 4 files changed, 168 insertions(+), 120 deletions(-) diff --git a/examples/htool_dfu.c b/examples/htool_dfu.c index 700b1c8..c56d235 100644 --- a/examples/htool_dfu.c +++ b/examples/htool_dfu.c @@ -30,59 +30,12 @@ #include "protocol/dfu_hostcmd.h" #include "protocol/opentitan_version.h" -static int dfu_update_count(struct opentitan_image_version* desired_romext, - struct opentitan_image_version* desired_app, - struct opentitan_get_version_resp* resp) { - // 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; - - struct opentitan_image_version* booted_romext = - &resp->rom_ext.slots[rom_ext_boot_slot]; - struct opentitan_image_version* staged_romext = - &resp->rom_ext.slots[rom_ext_stage_slot]; - struct opentitan_image_version* booted_app = &resp->app.slots[app_boot_slot]; - struct opentitan_image_version* staged_app = &resp->app.slots[app_stage_slot]; - - bool booted_needs_update = - (libhoth_ot_app_version_cmp_for_update(booted_app, desired_app) != 0) || - (libhoth_ot_rom_ext_version_cmp_for_update(booted_romext, - desired_romext) < 0); - - if (booted_needs_update) { - printf( - "The current bootslot is not the desired version. Performing DFU " - "update x2...\n"); - return 2; - } - - bool staging_needs_update = - (libhoth_ot_app_version_cmp_for_update(staged_app, desired_app) != 0) || - (libhoth_ot_rom_ext_version_cmp_for_update(staged_romext, - desired_romext) < 0); - - if (staging_needs_update) { - printf( - "Only the staging slot needs updating. Performing DFU update x1...\n "); - return 1; - } - - printf("Device is already at the desired version. No DFU update needed.\n"); - return 0; -} - int htool_dfu_update(const struct htool_invocation* inv) { struct libhoth_device* dev = htool_libhoth_device(); if (!dev) { 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)) { @@ -137,90 +90,41 @@ int htool_dfu_update(const struct htool_invocation* inv) { goto cleanup; } - // Populate rom_ext and app with the desired extracted versions from the image - retval = libhoth_extract_ot_bundle(image, statbuf.st_size, &desired_rom_ext, - &desired_app); - - if (retval != 0) { - fprintf(stderr, "Failed to extract bundle (%d)\n", retval); - goto cleanup2; - } - - // Get the current version of the device - retval = libhoth_opentitan_version(dev, &resp); - - if (retval != 0) { - fprintf(stderr, "Failed to get current version (%d)\n", retval); - goto cleanup2; - } - - if (!force && (desired_app.security_version < resp.bl0_min_sec_ver)) { - fprintf( - stderr, - "Desired application firmware security version %u is less than " - "currently enforced minimum application firmware security version %u\n", - desired_app.security_version, resp.bl0_min_sec_ver); - retval = -1; - goto cleanup2; - } - - int update_cnt = - force ? 2 : dfu_update_count(&desired_rom_ext, &desired_app, &resp); - - for (int i = 0; i < update_cnt; i++) { - libhoth_error err = - libhoth_dfu_update(dev, image, statbuf.st_size, complete_flags); - - if (err != HOTH_SUCCESS) { - htool_report_error("dfu_update", err); - fprintf(stderr, "DFU update failed (0x%016lx)\n", err); - libhoth_print_dfu_error(dev, NULL, (int)err); - retval = -1; - goto cleanup2; - } - - retval = libhoth_opentitan_version(dev, &resp); - if (retval != 0) { - fprintf(stderr, "Failed to get ot version after dfu update (%d)\n", - retval); - libhoth_print_dfu_error(dev, NULL, retval); - goto cleanup2; - } - - if (!libhoth_ot_check_update_successful(&resp, &desired_rom_ext, - &desired_app)) { - fprintf(stderr, "Boot slot is wrong after dfu update %d\n", i); - libhoth_print_dfu_error(dev, &resp, LIBHOTH_OK); - retval = -1; - goto cleanup2; + libhoth_error err = HOTH_SUCCESS; + if (force) { + for (int i = 0; i < 2; i++) { + err = libhoth_dfu_update(dev, image, statbuf.st_size, complete_flags); + if (err != HOTH_SUCCESS) { + break; + } } + } else { + err = libhoth_dfu_install_firmware(dev, image, statbuf.st_size, + complete_flags); } - libhoth_error update_err = - libhoth_update_complete(&resp, &desired_rom_ext, &desired_app); - if (update_err != HOTH_SUCCESS) { - fprintf(stderr, - "DFU update failed, running image does not match expected after %d " - "dfu updates\n", - update_cnt); - libhoth_print_dfu_error(dev, &resp, update_err); + if (err != HOTH_SUCCESS) { + htool_report_error("dfu_update", err); + fprintf(stderr, "DFU update failed (0x%016lx)\n", err); + libhoth_print_dfu_error(dev, NULL, err); retval = -1; - goto cleanup2; + } else { + retval = 0; } - int ret; - -cleanup2: - ret = munmap(image, statbuf.st_size); - if (ret != 0) { - fprintf(stderr, "munmap error: %d\n", ret); + { + int ret = munmap(image, statbuf.st_size); + if (ret != 0) { + fprintf(stderr, "munmap error: %d\n", ret); + } } -cleanup: - ret = close(fd); +cleanup: { + int ret = close(fd); if (ret != 0) { fprintf(stderr, "close error: %d\n", ret); } +} return retval; } diff --git a/protocol/BUILD b/protocol/BUILD index 604a531..ef1d1b5 100644 --- a/protocol/BUILD +++ b/protocol/BUILD @@ -552,8 +552,10 @@ cc_library( srcs = ["dfu_hostcmd.c"], hdrs = ["dfu_hostcmd.h"], deps = [ + ":dfu_check", ":host_cmd", ":libhoth_status", + ":opentitan_version", "//transports:libhoth_device", ], ) diff --git a/protocol/dfu_hostcmd.c b/protocol/dfu_hostcmd.c index 34924f8..265db7f 100644 --- a/protocol/dfu_hostcmd.c +++ b/protocol/dfu_hostcmd.c @@ -13,7 +13,10 @@ #include #include +#include "protocol/dfu_check.h" +#include "protocol/dfu_hostcmd.h" #include "protocol/host_cmd.h" +#include "protocol/opentitan_version.h" #include "protocol/status.h" static int generate_random_nonce(struct hoth_dfu_session_id* session_id) { @@ -100,3 +103,124 @@ libhoth_error libhoth_dfu_update(struct libhoth_device* dev, } return HOTH_SUCCESS; } + +static int dfu_update_count( + const struct opentitan_image_version* desired_romext, + const struct opentitan_image_version* desired_app, + const struct opentitan_get_version_resp* resp) { + 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; + + const struct opentitan_image_version* booted_romext = + &resp->rom_ext.slots[rom_ext_boot_slot]; + const struct opentitan_image_version* staged_romext = + &resp->rom_ext.slots[rom_ext_stage_slot]; + const struct opentitan_image_version* booted_app = + &resp->app.slots[app_boot_slot]; + const struct opentitan_image_version* staged_app = + &resp->app.slots[app_stage_slot]; + + bool booted_needs_update = + (libhoth_ot_app_version_cmp_for_update(booted_app, desired_app) != 0) || + (libhoth_ot_rom_ext_version_cmp_for_update(booted_romext, + desired_romext) < 0); + + if (booted_needs_update) { + printf( + "The current bootslot is not the desired version. Performing DFU " + "update x2...\n"); + return 2; + } + + bool staging_needs_update = + (libhoth_ot_app_version_cmp_for_update(staged_app, desired_app) != 0) || + (libhoth_ot_rom_ext_version_cmp_for_update(staged_romext, + desired_romext) < 0); + + if (staging_needs_update) { + printf( + "Only the staging slot needs updating. Performing DFU update x1...\n"); + return 1; + } + + printf("Device is already at the desired version. No DFU update needed.\n"); + return 0; +} + +libhoth_error libhoth_dfu_install_firmware(struct libhoth_device* dev, + const uint8_t* image, + size_t image_size, + uint32_t complete_flags) { + if (dev == NULL || image == NULL) { + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); + } + + struct opentitan_image_version desired_rom_ext = {0}; + struct opentitan_image_version desired_app = {0}; + struct opentitan_get_version_resp resp = {0}; + + int retval = libhoth_extract_ot_bundle(image, image_size, &desired_rom_ext, + &desired_app); + if (retval != 0) { + fprintf(stderr, "Failed to extract bundle (%d)\n", retval); + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + retval); + } + + retval = libhoth_opentitan_version(dev, &resp); + if (retval != 0) { + fprintf(stderr, "Failed to get current version (%d)\n", retval); + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + retval); + } + + if (desired_app.security_version < resp.bl0_min_sec_ver) { + fprintf( + stderr, + "Desired application firmware security version %u is less than " + "currently enforced minimum application firmware security version %u\n", + desired_app.security_version, resp.bl0_min_sec_ver); + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); + } + + int update_cnt = dfu_update_count(&desired_rom_ext, &desired_app, &resp); + + for (int i = 0; i < update_cnt; i++) { + libhoth_error err = + libhoth_dfu_update(dev, image, image_size, complete_flags); + if (err != HOTH_SUCCESS) { + return err; + } + + retval = libhoth_opentitan_version(dev, &resp); + if (retval != 0) { + fprintf(stderr, "Failed to get ot version after dfu update (%d)\n", + retval); + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + retval); + } + + if (!libhoth_ot_check_update_successful(&resp, &desired_rom_ext, + &desired_app)) { + fprintf(stderr, "Boot slot is wrong after dfu update %d\n", i); + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_FAIL); + } + } + + libhoth_error update_err = + libhoth_update_complete(&resp, &desired_rom_ext, &desired_app); + if (update_err != HOTH_SUCCESS) { + fprintf(stderr, + "DFU update failed, running image does not match expected after %d " + "dfu updates\n", + update_cnt); + return update_err; + } + + return HOTH_SUCCESS; +} diff --git a/protocol/dfu_hostcmd.h b/protocol/dfu_hostcmd.h index be631a2..6ba3d3c 100644 --- a/protocol/dfu_hostcmd.h +++ b/protocol/dfu_hostcmd.h @@ -104,6 +104,24 @@ libhoth_error libhoth_dfu_update(struct libhoth_device* dev, const uint8_t* image, size_t image_size, uint32_t complete_flags); +/** + * @brief Install firmware onto the device using DFU host commands. + * + * Performs whatever updates are necessary to ensure that both internal A/B + * partitions match the provided firmware image. + * + * @param dev The libhoth device handle. + * @param image A pointer to the firmware image data. + * @param image_size The size of the firmware image in bytes. + * @param complete_flags Flags to be passed to the DFU complete command, + * e.g., HOTH_DFU_COMPLETE_FLAGS_COLD_RESTART. + * @return HOTH_SUCCESS on success, or a libhoth_error code on failure. + */ +libhoth_error libhoth_dfu_install_firmware(struct libhoth_device* dev, + const uint8_t* image, + size_t image_size, + uint32_t complete_flags); + #ifdef __cplusplus } #endif