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