static int host_processor_filtered_validate_flash()

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;
}