in core/host_fw/host_processor_dual.c [75:190]
static int host_processor_dual_flash_rollback (struct host_processor *host,
const struct hash_engine *hash, const struct rsa_engine *rsa, bool disable_bypass,
bool no_reset)
{
struct host_processor_filtered *dual = (struct host_processor_filtered*) host;
const struct pfm *active_pfm;
struct host_flash_manager_rw_regions rw_list;
const struct spi_flash *ro_flash;
const struct spi_flash *rw_flash;
uint32_t dev_size;
int status = 0;
if ((dual == NULL) || (hash == NULL) || (rsa == NULL)) {
return HOST_PROCESSOR_INVALID_ARGUMENT;
}
platform_mutex_lock (&dual->lock);
debug_log_create_entry (DEBUG_LOG_SEVERITY_WARNING, DEBUG_LOG_COMPONENT_HOST_FW,
HOST_LOGGING_ROLLBACK_STARTED, dual->base.port, 0);
active_pfm = dual->pfm->get_active_pfm (dual->pfm);
if (active_pfm && !host_state_manager_is_flash_supported (dual->state)) {
status = HOST_PROCESSOR_FLASH_NOT_SUPPORTED;
goto exit;
}
if ((!active_pfm && !disable_bypass) ||
(active_pfm && (!host_state_manager_is_inactive_dirty (dual->state) ||
host_state_manager_is_bypass_mode (dual->state)))) {
if (host_state_manager_is_bypass_mode (dual->state) && disable_bypass) {
status = HOST_PROCESSOR_NO_ROLLBACK;
goto exit;
}
if (!no_reset && !dual->reset_pulse) {
dual->control->hold_processor_in_reset (dual->control, true);
}
status = dual->flash->set_flash_for_rot_access (dual->flash, dual->control);
if (status != 0) {
goto return_flash;
}
if (active_pfm) {
if (!host_state_manager_is_bypass_mode (dual->state)) {
/* Even though the dirty state hasn't been set, we still need to make sure the other
* flash contains a good image prior to activating it. */
status = dual->flash->validate_read_write_flash (dual->flash, active_pfm, hash, rsa,
&rw_list);
if (status == 0) {
host_processor_filtered_swap_flash (dual, &rw_list, NULL, true);
dual->flash->free_read_write_regions (dual->flash, &rw_list);
observable_notify_observers (&dual->base.observable,
offsetof (struct host_processor_observer, on_active_mode));
}
}
else {
/* If we are in forced bypass mode, just switch flashes. */
host_processor_dual_force_bypass_mode (dual, true);
}
}
else {
/* We are not in active mode yet, so just copy the contents from the second flash
* entirely into the boot flash. */
ro_flash = dual->flash->get_read_only_flash (dual->flash);
rw_flash = dual->flash->get_read_write_flash (dual->flash);
spi_flash_get_device_size (ro_flash, &dev_size);
status = spi_flash_chip_erase (ro_flash);
if (status != 0) {
goto return_flash;
}
status = flash_copy_ext_to_blank_and_verify (&ro_flash->base, 0, &rw_flash->base, 0,
dev_size);
}
return_flash:
host_processor_filtered_set_host_flash_access (dual);
if (!no_reset) {
if (dual->reset_pulse) {
dual->control->hold_processor_in_reset (dual->control, true);
platform_msleep (dual->reset_pulse);
}
dual->control->hold_processor_in_reset (dual->control, false);
}
}
else if (!active_pfm) {
status = HOST_PROCESSOR_NO_ROLLBACK;
}
else {
status = HOST_PROCESSOR_ROLLBACK_DIRTY;
}
exit:
if (active_pfm) {
dual->pfm->free_pfm (dual->pfm, active_pfm);
}
if (status == 0) {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_HOST_FW,
HOST_LOGGING_ROLLBACK_COMPLETED, dual->base.port, 0);
}
else {
debug_log_create_entry (DEBUG_LOG_SEVERITY_ERROR, DEBUG_LOG_COMPONENT_HOST_FW,
HOST_LOGGING_ROLLBACK_FAILED, status, dual->base.port);
}
platform_mutex_unlock (&dual->lock);
return status;
}