static int host_processor_dual_flash_rollback()

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