in core/host_fw/host_processor_filtered.c [443:610]
static int host_processor_filtered_validate_flash (struct host_processor_filtered *host,
const struct hash_engine *hash, const struct rsa_engine *rsa, const struct pfm *pfm,
const struct pfm *active, bool is_pending, bool is_bypass, bool skip_ro, bool skip_ro_config,
bool apply_filter_cfg, bool is_validated, bool single, bool *config_fail)
{
struct host_flash_manager_rw_regions rw_list;
int status = HOST_PROCESSOR_RW_SKIPPED;
int dirty_fail = 0;
bool checked_rw = true;
bool failed_rw = false;
bool pfm_dirty = host_state_manager_is_pfm_dirty (host->state);
if (!is_bypass && host_state_manager_is_inactive_dirty (host->state)) {
if (!is_validated) {
host_state_manager_set_run_time_validation (host->state, HOST_STATE_PREVALIDATED_NONE);
status = host->flash->validate_read_write_flash (host->flash, pfm, hash, rsa, &rw_list);
}
else {
status = host->flash->get_flash_read_write_regions (host->flash, pfm, true, &rw_list);
}
if (status != 0) {
failed_rw = true;
}
if (is_pending) {
debug_log_create_entry ((status ==
0) ? DEBUG_LOG_SEVERITY_INFO : DEBUG_LOG_SEVERITY_WARNING,
DEBUG_LOG_COMPONENT_HOST_FW, (is_validated) ?
HOST_LOGGING_PENDING_ACTIVATE_FW_UPDATE :
HOST_LOGGING_PENDING_VERIFY_FW_UPDATE, host->base.port, status);
}
else {
debug_log_create_entry ((status ==
0) ? DEBUG_LOG_SEVERITY_INFO : DEBUG_LOG_SEVERITY_WARNING,
DEBUG_LOG_COMPONENT_HOST_FW, (is_validated) ?
HOST_LOGGING_ACTIVE_ACTIVATE_FW_UPDATE :
HOST_LOGGING_ACTIVE_VERIFY_FW_UPDATE, host->base.port, status);
}
if (status == 0) {
if (apply_filter_cfg) {
if (is_pending) {
host_processor_filtered_swap_flash (host, &rw_list, host->pfm, false);
}
else {
host_processor_filtered_swap_flash (host, &rw_list, NULL, false);
}
observable_notify_observers (&host->base.observable,
offsetof (struct host_processor_observer, on_active_mode));
}
else {
status = host->filter->clear_flash_dirty_state (host->filter);
if (status == 0) {
if (is_pending) {
host_state_manager_set_pfm_dirty (host->state, false);
host_state_manager_set_run_time_validation (host->state,
HOST_STATE_PREVALIDATED_FLASH_AND_PFM);
}
else {
host_state_manager_set_run_time_validation (host->state,
HOST_STATE_PREVALIDATED_FLASH);
}
}
else {
*config_fail = true;
}
}
host->flash->free_read_write_regions (host->flash, &rw_list);
if (status != 0) {
goto exit;
}
}
else {
if (!single && ((skip_ro && !is_pending) || is_validated) && apply_filter_cfg) {
/* R/W verification failed with no RO verification going to take place. We need to
* restore R/W regions here using the active PFM. */
host_processor_filtered_restore_read_write_data (host, NULL,
(is_pending) ? active : pfm);
}
if (IS_VALIDATION_FAILURE (status)) {
dirty_fail = status;
if (single && is_pending) {
/* Validation is only run against one flash, so clear the PFM dirty state. */
host_state_manager_set_pfm_dirty (host->state, false);
}
}
else if (is_pending && !is_validated) {
host_state_manager_set_pfm_dirty (host->state, true);
}
}
}
else {
checked_rw = false;
}
if (!skip_ro && (status != 0) && (!is_pending || is_bypass || pfm_dirty) &&
(!single || !checked_rw)) {
status = host->flash->validate_read_only_flash (host->flash, pfm, active, hash, rsa,
is_bypass, &rw_list);
if (is_pending) {
debug_log_create_entry ((status ==
0) ? DEBUG_LOG_SEVERITY_INFO : DEBUG_LOG_SEVERITY_WARNING,
DEBUG_LOG_COMPONENT_HOST_FW, HOST_LOGGING_PENDING_VERIFY_CURRENT, host->base.port,
status);
}
else {
debug_log_create_entry ((status ==
0) ? DEBUG_LOG_SEVERITY_INFO : DEBUG_LOG_SEVERITY_ERROR,
DEBUG_LOG_COMPONENT_HOST_FW, HOST_LOGGING_ACTIVE_VERIFY_CURRENT, host->base.port,
status);
}
if (status == 0) {
if (is_bypass) {
host_processor_filtered_initialize_protection (host, &rw_list);
}
else if (apply_filter_cfg && failed_rw) {
host_processor_filtered_restore_read_write_data (host, &rw_list, NULL);
}
if (is_pending) {
host->pfm->base.activate_pending_manifest (&host->pfm->base);
}
if (apply_filter_cfg) {
if (!is_bypass && !skip_ro_config) {
host_processor_filtered_config_flash (host);
}
host_processor_filtered_config_rw (host, &rw_list);
observable_notify_observers (&host->base.observable,
offsetof (struct host_processor_observer, on_active_mode));
}
host->flash->free_read_write_regions (host->flash, &rw_list);
}
else if (is_pending && IS_VALIDATION_FAILURE (status) &&
(!checked_rw || (checked_rw && (dirty_fail != 0)))) {
/* If there was a validation failure on both flash devices with the pending PFM, clear
* the dirty PFM state. */
host_state_manager_set_pfm_dirty (host->state, false);
}
}
/* Handle situations where the flash dirty state needs to be cleared. Do this last to ensure
* all other operations fully complete before we wipe the indication that flash had been
* modified and needed authentication. */
if ((dirty_fail != 0) &&
(!single && checked_rw &&
(!is_pending || is_validated || (status == 0) ||
(is_pending && !active && skip_ro_config)))) {
dirty_fail = host->filter->clear_flash_dirty_state (host->filter);
if (dirty_fail == 0) {
host_state_manager_save_inactive_dirty (host->state, false);
}
}
exit:
return status;
}