int host_processor_filtered_update_verification()

in core/host_fw/host_processor_filtered.c [831:1014]


int host_processor_filtered_update_verification (struct host_processor_filtered *host,
	const struct hash_engine *hash, const struct rsa_engine *rsa, bool single, bool reset,
	int bypass_status)
{
	const struct pfm *active_pfm;
	const struct pfm *pending_pfm;
	int status = 0;
	enum host_state_prevalidated flash_checked = HOST_STATE_PREVALIDATED_NONE;
	bool prevalidated;
	bool bypass;
	bool dirty;
	bool only_validated = false;
	bool notified = !reset;
	bool validate_flash;
	bool reset_flash = host->reset_flash && reset;
	bool no_pfm;
	bool no_state_change;

	if ((hash == NULL) || (rsa == NULL)) {
		return HOST_PROCESSOR_INVALID_ARGUMENT;
	}

	if (!host_state_manager_is_flash_supported (host->state)) {
		return HOST_PROCESSOR_FLASH_NOT_SUPPORTED;
	}

	platform_mutex_lock (&host->lock);

	active_pfm = host->pfm->get_active_pfm (host->pfm);
	pending_pfm = host->pfm->get_pending_pfm (host->pfm);
	if (!active_pfm && !pending_pfm) {
		status = bypass_status;
	}

	bypass = host_state_manager_is_bypass_mode (host->state);
	dirty = host_state_manager_is_inactive_dirty (host->state);

	no_pfm = !active_pfm && !pending_pfm;
	validate_flash = pending_pfm || (no_pfm && !bypass) || (active_pfm && (dirty || bypass));
	no_state_change = !dirty && !bypass && !host_state_manager_is_pfm_dirty (host->state) &&
		(active_pfm || (pending_pfm && !active_pfm));

	if (validate_flash || reset_flash) {
		/* If nothing has changed since the last validation, just exit. */
		if (!reset_flash && no_state_change) {
			goto exit;
		}

		if (reset && !host->reset_pulse) {
			host->control->hold_processor_in_reset (host->control, true);
		}

		status = host->flash->set_flash_for_rot_access (host->flash, host->control);
		if (reset_flash && (status == 0)) {
			host_processor_filtered_reset_host_flash (host);
		}

		if ((status != 0) || !validate_flash || no_state_change) {
			if (!validate_flash) {
				host_processor_filtered_clear_host_dirty_state (host, no_pfm);
			}

			goto return_flash;
		}

		if (pending_pfm) {
			int empty_status;

			status = host_processor_filtered_check_force_bypass_mode (host, &active_pfm,
				&pending_pfm, &empty_status);
			if (status != 0) {
				goto return_flash;
			}

			status = empty_status;
			if ((status != 0) && (!active_pfm || (active_pfm && !dirty))) {
				goto return_flash;
			}
		}

		if (!bypass) {
			flash_checked = host_state_manager_get_run_time_validation (host->state);
		}
		host_state_manager_set_run_time_validation (host->state, HOST_STATE_PREVALIDATED_NONE);

		if (pending_pfm) {
			if (bypass || !active_pfm) {
				prevalidated = false;
			}
			else {
				switch (flash_checked) {
					case HOST_STATE_PREVALIDATED_FLASH_AND_PFM:
						prevalidated = !host_state_manager_is_pfm_dirty (host->state);
						break;

					case HOST_STATE_PREVALIDATED_FLASH:
						if (!host_state_manager_is_pfm_dirty (host->state)) {
							status = HOST_PROCESSOR_NOTHING_TO_VERIFY;
						}
					/* fall through */ /* no break */

					default:
						prevalidated = false;
						break;
				}
			}

			if (status == 0) {
				only_validated = prevalidated;
				status = host_processor_filtered_validate_flash (host, hash, rsa, pending_pfm,
					bypass ? NULL : active_pfm, true, bypass, only_validated, true, true,
					prevalidated, single, NULL);
			}
		}
		else if (status == 0) {
			host_state_manager_set_pfm_dirty (host->state, false);
		}

		if ((!pending_pfm && active_pfm) ||
			(active_pfm && (status != 0) && !only_validated && (dirty || bypass))) {
			if (flash_checked == HOST_STATE_PREVALIDATED_FLASH) {
				prevalidated = true;
			}
			else {
				prevalidated = false;
			}

			status = host_processor_filtered_validate_flash (host, hash, rsa, active_pfm, NULL,
				false, bypass, !bypass, true, true, prevalidated, single, NULL);
		}
		else if (!pending_pfm && !active_pfm) {
			/* When there is no PFM available, ensure the system is running in bypass mode.  PFMs
			 * that were present at POR could have been cleared, so apply bypass configuration. */
			host->filter->clear_flash_dirty_state (host->filter);
			host_state_manager_save_inactive_dirty (host->state, false);
			host_state_manager_set_pfm_dirty (host->state, false);

			if (!bypass) {
				host_processor_filtered_config_bypass (host);
			}
		}

return_flash:
		if (!notified) {
			observable_notify_observers (&host->base.observable,
				offsetof (struct host_processor_observer, on_soft_reset));
			notified = true;
		}

		host_processor_filtered_set_host_flash_access (host);

		if (reset && host->reset_pulse) {
			host->control->hold_processor_in_reset (host->control, true);
			platform_msleep (host->reset_pulse);
		}
	}
	else {
		host_processor_filtered_clear_host_dirty_state (host, no_pfm);
	}

exit:
	if (!notified) {
		observable_notify_observers (&host->base.observable,
			offsetof (struct host_processor_observer, on_soft_reset));
	}

	if (active_pfm) {
		host->pfm->free_pfm (host->pfm, active_pfm);
	}
	if (pending_pfm) {
		host->pfm->free_pfm (host->pfm, pending_pfm);
	}

	if (reset) {
		/* Some implementations will set the processor reset independently of this flow, so we need
		 * to be sure the reset is always released after soft reset processing.  Releasing the reset
		 * in cases where the reset is never set is not an issue. */
		host->control->hold_processor_in_reset (host->control, false);
	}

	platform_mutex_unlock (&host->lock);

	return status;
}