core/host_fw/host_flash_manager_dual.c (299 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stddef.h> #include <stdlib.h> #include <string.h> #include "host_flash_manager_dual.h" #include "host_fw_util.h" #include "common/unused.h" static const struct spi_flash* host_flash_manager_dual_get_read_only_flash ( struct host_flash_manager *manager) { struct host_flash_manager_dual *dual = (struct host_flash_manager_dual*) manager; if (dual == NULL) { return NULL; } if (host_state_manager_get_read_only_flash (dual->host_state) == SPI_FILTER_CS_0) { return dual->flash_cs0; } else { return dual->flash_cs1; } } static const struct spi_flash* host_flash_manager_dual_get_read_write_flash ( struct host_flash_manager *manager) { struct host_flash_manager_dual *dual = (struct host_flash_manager_dual*) manager; if (dual == NULL) { return NULL; } if (host_state_manager_get_read_only_flash (dual->host_state) == SPI_FILTER_CS_0) { return dual->flash_cs1; } else { return dual->flash_cs0; } } static int host_flash_manager_dual_validate_read_only_flash (struct host_flash_manager *manager, const struct pfm *pfm, const struct pfm *good_pfm, const struct hash_engine *hash, const struct rsa_engine *rsa, bool full_validation, struct host_flash_manager_rw_regions *host_rw) { int status; if ((manager == NULL) || (pfm == NULL) || (hash == NULL) || (rsa == NULL) || (host_rw == NULL)) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } if (good_pfm && !full_validation) { status = host_flash_manager_validate_pfm (pfm, good_pfm, hash, rsa, host_flash_manager_dual_get_read_only_flash (manager), host_rw); } else { status = host_flash_manager_validate_flash (pfm, hash, rsa, full_validation, host_flash_manager_dual_get_read_only_flash (manager), host_rw); } return status; } static int host_flash_manager_dual_validate_read_write_flash (struct host_flash_manager *manager, const struct pfm *pfm, const struct hash_engine *hash, const struct rsa_engine *rsa, struct host_flash_manager_rw_regions *host_rw) { if ((manager == NULL) || (pfm == NULL) || (hash == NULL) || (rsa == NULL) || (host_rw == NULL)) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } return host_flash_manager_validate_flash (pfm, hash, rsa, true, host_flash_manager_dual_get_read_write_flash (manager), host_rw); } static int host_flash_manager_dual_get_flash_read_write_regions (struct host_flash_manager *manager, const struct pfm *pfm, bool rw_flash, struct host_flash_manager_rw_regions *host_rw) { if ((manager == NULL) || (pfm == NULL) || (host_rw == NULL)) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } return host_flash_manager_get_flash_read_write_regions ((rw_flash) ? host_flash_manager_dual_get_read_write_flash (manager) : host_flash_manager_dual_get_read_only_flash (manager), pfm, host_rw); } static int host_flash_manager_dual_config_spi_filter_flash_type (struct host_flash_manager *manager) { struct host_flash_manager_dual *dual = (struct host_flash_manager_dual*) manager; if (dual == NULL) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } return host_flash_manager_config_spi_filter_flash_type (dual->flash_cs0, dual->flash_cs1, dual->filter, dual->mfg_handler); } static int host_flash_manager_dual_config_spi_filter_flash_devices ( struct host_flash_manager *manager) { struct host_flash_manager_dual *dual = (struct host_flash_manager_dual*) manager; spi_filter_cs ro; if (dual == NULL) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } ro = host_state_manager_get_read_only_flash (dual->host_state); return dual->filter->set_ro_cs (dual->filter, ro); } /** * Copy the read/write data regions from one flash to another. * * @param manager The flash manager to use for the data migration. * @param from The flash device to copy from. * @param writable The list of read/write regions that should be migrated. * * @return 0 if the data migration was successful or an error code. */ static int host_flash_manager_dual_migrate_rw_data (struct host_flash_manager_dual *manager, spi_filter_cs from, struct host_flash_manager_rw_regions *host_rw) { int status; if (from == SPI_FILTER_CS_0) { status = host_fw_migrate_read_write_data_multiple_fw (&manager->flash_cs1->base, host_rw->writable, host_rw->count, &manager->flash_cs0->base, NULL, 0); } else { status = host_fw_migrate_read_write_data_multiple_fw (&manager->flash_cs0->base, host_rw->writable, host_rw->count, &manager->flash_cs1->base, NULL, 0); } return status; } static int host_flash_manager_dual_swap_flash_devices (struct host_flash_manager *manager, struct host_flash_manager_rw_regions *host_rw, const struct pfm_manager *used_pending) { struct host_flash_manager_dual *dual = (struct host_flash_manager_dual*) manager; spi_filter_cs rw; int status; if (dual == NULL) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } /* Clear the dirty bit in the SPI filter. */ status = dual->filter->clear_flash_dirty_state (dual->filter); if (status != 0) { return status; } /* Configure the SPI filter to switch the read and write flashes. */ rw = (host_state_manager_get_read_only_flash (dual->host_state) == SPI_FILTER_CS_0) ? SPI_FILTER_CS_1 : SPI_FILTER_CS_0; status = dual->filter->set_ro_cs (dual->filter, rw); if (status != 0) { return status; } /* Migrate the R/W data to the new write flash. */ if (host_rw) { status = host_flash_manager_dual_migrate_rw_data (dual, rw, host_rw); } /* Save the current flash configuration. */ if (status == 0) { state_manager_block_non_volatile_state_storage (&dual->host_state->base, true); host_state_manager_save_read_only_flash (dual->host_state, rw); host_state_manager_save_inactive_dirty (dual->host_state, false); if (used_pending) { used_pending->base.activate_pending_manifest (&used_pending->base); } state_manager_block_non_volatile_state_storage (&dual->host_state->base, false); } return status; } static int host_flash_manager_dual_initialize_flash_protection (struct host_flash_manager *manager, struct host_flash_manager_rw_regions *host_rw) { struct host_flash_manager_dual *dual = (struct host_flash_manager_dual*) manager; spi_filter_cs ro; const struct spi_flash *ro_flash; const struct spi_flash *rw_flash; int status; int addr_4byte; if ((dual == NULL) || (host_rw == NULL)) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } /* Make sure both flash devices are running with the same address mode. */ ro_flash = host_flash_manager_dual_get_read_only_flash (manager); rw_flash = host_flash_manager_dual_get_read_write_flash (manager); addr_4byte = spi_flash_is_4byte_address_mode (ro_flash); if (ROT_IS_ERROR (addr_4byte)) { return addr_4byte; } if (addr_4byte != spi_flash_is_4byte_address_mode (rw_flash)) { status = spi_flash_enable_4byte_address_mode (rw_flash, addr_4byte); if (status != 0) { return status; } } /* Make the R/W data available on the R/W flash device. */ ro = host_state_manager_get_read_only_flash (dual->host_state); status = host_flash_manager_dual_migrate_rw_data (dual, ro, host_rw); if (status != 0) { return status; } /* Protection is being initialized, so the R/W flash can't be dirty yet. */ status = dual->filter->clear_flash_dirty_state (dual->filter); if (status != 0) { return status; } host_state_manager_save_inactive_dirty (dual->host_state, false); /* Make sure the SPI filter address mode matches the mode of the physical devices. * * If the device address mode is fixed, this was already configured during initial filter setup * and doesn't need to be done again. */ if (!spi_flash_is_address_mode_fixed (ro_flash)) { status = dual->filter->set_addr_byte_mode (dual->filter, (addr_4byte == 1) ? SPI_FILTER_ADDRESS_MODE_4 : SPI_FILTER_ADDRESS_MODE_3); if (status != 0) { return status; } } /* Turn on the SPI filter. */ status = dual->filter->set_filter_mode (dual->filter, SPI_FILTER_FLASH_DUAL); if (status != 0) { return status; } return dual->filter->set_ro_cs (dual->filter, ro); } static int host_flash_manager_dual_restore_flash_read_write_regions ( struct host_flash_manager *manager, struct host_flash_manager_rw_regions *host_rw) { const struct spi_flash *rw_flash; const struct spi_flash *ro_flash; if ((manager == NULL) || (host_rw == NULL)) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } rw_flash = host_flash_manager_dual_get_read_write_flash (manager); ro_flash = host_flash_manager_dual_get_read_only_flash (manager); return host_fw_restore_read_write_data_multiple_fw (&rw_flash->base, &ro_flash->base, host_rw->writable, host_rw->count); } static int host_flash_manager_dual_set_flash_for_rot_access (struct host_flash_manager *manager, const struct host_control *control) { struct host_flash_manager_dual *dual = (struct host_flash_manager_dual*) manager; if ((dual == NULL) || (control == NULL)) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } return host_flash_manager_set_flash_for_rot_access (control, dual->filter, dual->flash_cs0, dual->flash_cs1, dual->flash_init); } static int host_flash_manager_dual_set_flash_for_host_access (struct host_flash_manager *manager, const struct host_control *control) { struct host_flash_manager_dual *dual = (struct host_flash_manager_dual*) manager; if ((dual == NULL) || (control == NULL)) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } return host_flash_manager_set_flash_for_host_access (control, dual->filter); } static int host_flash_manager_dual_host_has_flash_access (struct host_flash_manager *manager, const struct host_control *control) { struct host_flash_manager_dual *dual = (struct host_flash_manager_dual*) manager; if ((dual == NULL) || (control == NULL)) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } return host_flash_manager_host_has_flash_access (control, dual->filter); } static int host_flash_manager_dual_reset_flash (struct host_flash_manager *manager) { struct host_flash_manager_dual *dual = (struct host_flash_manager_dual*) manager; int status = 0; if (dual == NULL) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } status = spi_flash_reset_device (dual->flash_cs0); if (status != 0) { return status; } return spi_flash_reset_device (dual->flash_cs1); } /** * Initialize the manager for dual host flash devices. * * @param manager The flash manager to initialize. * @param cs0 The flash device connected to chip select 0. * @param cs1 The flash device connected to chip select 1. * @param host_state The manager for host state information. * @param filter The SPI filter for the protected flash. * @param mfg_handler The SPI filter handler for configuring the flash device manufacturer. * * @return 0 if the manager was successfully initialized or an error code. */ int host_flash_manager_dual_init (struct host_flash_manager_dual *manager, const struct spi_flash *cs0, const struct spi_flash *cs1, struct host_state_manager *host_state, const struct spi_filter_interface *filter, const struct flash_mfg_filter_handler *mfg_handler) { if ((manager == NULL) || (cs0 == NULL) || (cs1 == NULL) || (host_state == NULL) || (filter == NULL) || (mfg_handler == NULL)) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } memset (manager, 0, sizeof (struct host_flash_manager_dual)); manager->base.get_read_only_flash = host_flash_manager_dual_get_read_only_flash; manager->base.get_read_write_flash = host_flash_manager_dual_get_read_write_flash; manager->base.validate_read_only_flash = host_flash_manager_dual_validate_read_only_flash; manager->base.validate_read_write_flash = host_flash_manager_dual_validate_read_write_flash; manager->base.get_flash_read_write_regions = host_flash_manager_dual_get_flash_read_write_regions; manager->base.free_read_write_regions = host_flash_manager_free_read_write_regions; manager->base.config_spi_filter_flash_type = host_flash_manager_dual_config_spi_filter_flash_type; manager->base.config_spi_filter_flash_devices = host_flash_manager_dual_config_spi_filter_flash_devices; manager->base.swap_flash_devices = host_flash_manager_dual_swap_flash_devices; manager->base.initialize_flash_protection = host_flash_manager_dual_initialize_flash_protection; manager->base.restore_flash_read_write_regions = host_flash_manager_dual_restore_flash_read_write_regions; manager->base.set_flash_for_rot_access = host_flash_manager_dual_set_flash_for_rot_access; manager->base.set_flash_for_host_access = host_flash_manager_dual_set_flash_for_host_access; manager->base.host_has_flash_access = host_flash_manager_dual_host_has_flash_access; manager->base.reset_flash = host_flash_manager_dual_reset_flash; manager->flash_cs0 = cs0; manager->flash_cs1 = cs1; manager->host_state = host_state; manager->filter = filter; manager->mfg_handler = mfg_handler; return 0; } /** * Initialize the manager for dual host flash devices. The interfaces to the flash devices may be * uninitialized, but an initialization manager is provided to ensure they get initialized prior to * use. * * @param manager The flash manager to initialize. * @param cs0 The flash device connected to chip select 0. * @param cs1 The flash device connected to chip select 1. * @param host_state The manager for host state information. * @param filter The SPI filter for the protected flash. * @param mfg_handler The SPI filter handler for configuring the flash device manufacturer. * @param flash_init The initialization manager for SPI flash interfaces. * * @return 0 if the manager was successfully initialized or an error code. */ int host_flash_manager_dual_init_with_managed_flash_initialization ( struct host_flash_manager_dual *manager, const struct spi_flash *cs0, const struct spi_flash *cs1, struct host_state_manager *host_state, const struct spi_filter_interface *filter, const struct flash_mfg_filter_handler *mfg_handler, struct host_flash_initialization *flash_init) { int status; if (flash_init == NULL) { return HOST_FLASH_MGR_INVALID_ARGUMENT; } status = host_flash_manager_dual_init (manager, cs0, cs1, host_state, filter, mfg_handler); if (status != 0) { return status; } manager->flash_init = flash_init; return 0; } /** * Release the resources used for dual host flash management. * * @param manager The manager to release. */ void host_flash_manager_dual_release (struct host_flash_manager_dual *manager) { UNUSED (manager); }