core/firmware/impactful_update_handler.c (103 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stddef.h> #include <stdlib.h> #include <string.h> #include "firmware_logging.h" #include "impactful_update_handler.h" #include "common/type_cast.h" #include "common/unused.h" int impactful_update_handler_start_update (const struct firmware_update_control *update) { const struct impactful_update_handler *handler = TO_DERIVED_TYPE (update, const struct impactful_update_handler, base_ctrl); if (update == NULL) { return IMPACTFUL_UPDATE_INVALID_ARGUMENT; } /* In order for this instance to get called by the event task, it needs to submit the event * notification directly. Otherwise, the contained firmware_update_handler instance would be * provided as part of the notification. * * Since this is bypassing the start_update call of the contained instance, it will not work as * expected with firmware_update_handler implementations that need to do more than just schedule * the event. */ return firmware_update_handler_submit_event (handler->update, &handler->base_event, FIRMWARE_UPDATE_HANDLER_ACTION_RUN_UPDATE, NULL, 0); } int impactful_update_handler_get_status (const struct firmware_update_control *update) { const struct impactful_update_handler *handler = TO_DERIVED_TYPE (update, const struct impactful_update_handler, base_ctrl); if (update == NULL) { return UPDATE_STATUS_UNKNOWN; } return handler->update->base_ctrl.get_status (&handler->update->base_ctrl); } int32_t impactful_update_handler_get_remaining_len (const struct firmware_update_control *update) { const struct impactful_update_handler *handler = TO_DERIVED_TYPE (update, const struct impactful_update_handler, base_ctrl); if (update == NULL) { return 0; } return handler->update->base_ctrl.get_remaining_len (&handler->update->base_ctrl); } int impactful_update_handler_prepare_staging (const struct firmware_update_control *update, size_t size) { const struct impactful_update_handler *handler = TO_DERIVED_TYPE (update, const struct impactful_update_handler, base_ctrl); if (update == NULL) { return IMPACTFUL_UPDATE_INVALID_ARGUMENT; } return handler->update->base_ctrl.prepare_staging (&handler->update->base_ctrl, size); } int impactful_update_handler_write_staging (const struct firmware_update_control *update, uint8_t *buf, size_t buf_len) { const struct impactful_update_handler *handler = TO_DERIVED_TYPE (update, const struct impactful_update_handler, base_ctrl); if (update == NULL) { return IMPACTFUL_UPDATE_INVALID_ARGUMENT; } return handler->update->base_ctrl.write_staging (&handler->update->base_ctrl, buf, buf_len); } void impactful_update_handler_execute (const struct event_task_handler *handler, struct event_task_context *context, bool *reset) { const struct impactful_update_handler *fw = TO_DERIVED_TYPE (handler, const struct impactful_update_handler, base_event); int status; fw->update->base_event.execute (&fw->update->base_event, context, reset); /* Impactful operations only get executed after a firmware update has been executed. Ignore * any other events that may come here. */ if (context->action == FIRMWARE_UPDATE_HANDLER_ACTION_RUN_UPDATE) { /* Only run impactful operations if the firmware update was successful. This can be * determined by checking getting the current update status. */ status = fw->update->base_ctrl.get_status (&fw->update->base_ctrl); if (status == 0) { /* Impactful authorization is only valid for a single update. If this fails, * authorization will eventually time out, if configured to do so. */ status = fw->impactful->reset_authorization (fw->impactful); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_WARNING, DEBUG_LOG_COMPONENT_CERBERUS_FW, FIRMWARE_LOGGING_IMPACTFUL_RESET_AUTH_FAIL, status, 0); } status = fw->impactful->is_update_not_impactful (fw->impactful); if (status != 0) { /* The update has been determined to be impactful, so disable the device reset that * would normally apply the new firmware image. */ firmware_update_handler_set_update_status_with_error (fw->update, UPDATE_STATUS_SUCCESS_NO_RESET, status); debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CERBERUS_FW, FIRMWARE_LOGGING_IMPACTFUL_UPDATE, status, 0); *reset = false; } } } } /** * Initialize a firmware update handler with support for handling updates that are impactful. * * @param handler The update handler to initialize. * @param state Variable context for the impactful handler. THis must be uninitialized. * @param update The firmware update handler that will be used to execute firmware updates. * @param impactful An extension to the firmware update flow to handle impactful updates. * * @return 0 if the handler was initialized successfully or an error code. */ int impactful_update_handler_init (struct impactful_update_handler *handler, const struct firmware_update_handler *update, const struct impactful_update_interface *impactful) { if ((handler == NULL) || (update == NULL) || (impactful == NULL)) { return IMPACTFUL_UPDATE_INVALID_ARGUMENT; } memset (handler, 0, sizeof (*handler)); handler->base_ctrl.start_update = impactful_update_handler_start_update; handler->base_ctrl.get_status = impactful_update_handler_get_status; handler->base_ctrl.get_remaining_len = impactful_update_handler_get_remaining_len; handler->base_ctrl.prepare_staging = impactful_update_handler_prepare_staging; handler->base_ctrl.write_staging = impactful_update_handler_write_staging; handler->base_event.execute = impactful_update_handler_execute; handler->update = update; handler->impactful = impactful; return 0; } /** * Release the resources used by an impactful firmware update handler. * * @param handler The update handler to release. */ void impactful_update_handler_release (const struct impactful_update_handler *handler) { UNUSED (handler); }