core/manifest/pfm/pfm_manager_flash.c (166 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 "pfm_manager_flash.h" #include "host_fw/host_state_manager.h" #include "manifest/manifest_logging.h" /** * Get the PFM interface for a manifest on flash. * * @param manager The manager to query. * @param active Flag indicating if the interface for the active region should be returned. * Otherwise, the pending region will be returned. * * @return The requested PFM instance or null if there was an error. */ static const struct pfm* pfm_manager_flash_get_pfm (const struct pfm_manager_flash *manager, bool active) { const struct pfm_flash *flash; const struct manifest_manager_flash_region *region; if (manager == NULL) { return NULL; } region = manifest_manager_flash_get_manifest_region (&manager->manifest_manager, active); if (region == NULL) { return NULL; } flash = (const struct pfm_flash*) region->manifest; return &flash->base; } const struct pfm* pfm_manager_flash_get_active_pfm (const struct pfm_manager *manager) { const struct pfm_manager_flash *pfm_mgr = (const struct pfm_manager_flash*) manager; return pfm_manager_flash_get_pfm (pfm_mgr, true); } const struct pfm* pfm_manager_flash_get_pending_pfm (const struct pfm_manager *manager) { const struct pfm_manager_flash *pfm_mgr = (const struct pfm_manager_flash*) manager; return pfm_manager_flash_get_pfm (pfm_mgr, false); } void pfm_manager_flash_free_pfm (const struct pfm_manager *manager, const struct pfm *pfm) { const struct pfm_manager_flash *pfm_mgr = (const struct pfm_manager_flash*) manager; if (pfm_mgr == NULL) { return; } manifest_manager_flash_free_manifest (&pfm_mgr->manifest_manager, (const struct manifest*) pfm); } int pfm_manager_flash_activate_pending_manifest (const struct manifest_manager *manager) { const struct pfm_manager_flash *pfm_mgr = (const struct pfm_manager_flash*) manager; int status; if (pfm_mgr == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } status = manifest_manager_flash_activate_pending_manifest (&pfm_mgr->manifest_manager); if (status == 0) { host_state_manager_set_pfm_dirty (pfm_mgr->host_state, false); pfm_manager_on_pfm_activated (&pfm_mgr->base); } pfm_manager_on_pfm_activation_request (&pfm_mgr->base); return status; } int pfm_manager_flash_clear_pending_region (const struct manifest_manager *manager, size_t size) { const struct pfm_manager_flash *pfm_mgr = (const struct pfm_manager_flash*) manager; if (pfm_mgr == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } return manifest_manager_flash_clear_pending_region (&pfm_mgr->manifest_manager, size); } int pfm_manager_flash_write_pending_data (const struct manifest_manager *manager, const uint8_t *data, size_t length) { const struct pfm_manager_flash *pfm_mgr = (const struct pfm_manager_flash*) manager; if (pfm_mgr == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } return manifest_manager_flash_write_pending_data (&pfm_mgr->manifest_manager, data, length); } int pfm_manager_flash_verify_pending_manifest (const struct manifest_manager *manager) { const struct pfm_manager_flash *pfm_mgr = (const struct pfm_manager_flash*) manager; int status; if (pfm_mgr == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } status = manifest_manager_flash_verify_pending_manifest (&pfm_mgr->manifest_manager); if (status == 0) { host_state_manager_set_pfm_dirty (pfm_mgr->host_state, true); pfm_manager_on_pfm_verified (&pfm_mgr->base); } return status; } int pfm_manager_flash_clear_all_manifests (const struct manifest_manager *manager) { const struct pfm_manager_flash *pfm_mgr = (const struct pfm_manager_flash*) manager; int status; if (pfm_mgr == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } status = manifest_manager_flash_clear_all_manifests (&pfm_mgr->manifest_manager, false); if (status == 0) { pfm_manager_on_clear_active (&pfm_mgr->base); } return status; } /** * Initialize the manager for handling PFMs. * * @param manager The PFM manager to initialize. * @param state Variable context for the PFM manager. This must be uninitialized. * @param pfm_region1 The PFM instance for the first flash region that can hold a PFM. * This region does not need to have a valid PFM. The region is expected to a single flash * erase block as defined by FLASH_BLOCK_SIZE, aligned to the beginning of the block. * @param pfm_region2 The PFM instance for the second flash region that can hold a PFM. * This region does not need to have a valid PFM. The region is expected to a single flash erase * block as defined by FLASH_BLOCK_SIZE, aligned to the beginning of the block. * @param state_mgr The state information for PFM management. * @param hash The hash engine to be used for PFM validation. * @param verification The module to be used for PFM verification. * * @return 0 if the PFM manager was successfully initialized or an error code. */ int pfm_manager_flash_init (struct pfm_manager_flash *manager, struct pfm_manager_flash_state *state, const struct pfm_flash *pfm_region1, const struct pfm_flash *pfm_region2, struct host_state_manager *state_mgr, const struct hash_engine *hash, const struct signature_verification *verification) { return pfm_manager_flash_init_port (manager, state, pfm_region1, pfm_region2, state_mgr, hash, verification, -1); } /** * Initialize the manager for handling PFMs. The manager port identifier will be set as part of * initialization. * * @param manager The PFM manager to initialize. * @param state Variable context for the PFM manager. This must be uninitialized. * @param pfm_region1 The PFM instance for the first flash region that can hold a PFM. * This region does not need to have a valid PFM. The region is expected to a single flash * erase block as defined by FLASH_BLOCK_SIZE, aligned to the beginning of the block. * @param pfm_region2 The PFM instance for the second flash region that can hold a PFM. * This region does not need to have a valid PFM. The region is expected to a single flash erase * block as defined by FLASH_BLOCK_SIZE, aligned to the beginning of the block. * @param state_mgr The state information for PFM management. * @param hash The hash engine to be used for PFM validation. * @param verification The module to be used for PFM verification. * @param port The port identifier to set. A negative port ID will use the default value. * * @return 0 if the PFM manager was successfully initialized or an error code. */ int pfm_manager_flash_init_port (struct pfm_manager_flash *manager, struct pfm_manager_flash_state *state, const struct pfm_flash *pfm_region1, const struct pfm_flash *pfm_region2, struct host_state_manager *state_mgr, const struct hash_engine *hash, const struct signature_verification *verification, int port) { int status; if ((manager == NULL) || (state == NULL) || (pfm_region1 == NULL) || (pfm_region2 == NULL) || (state_mgr == NULL)) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } memset (manager, 0, sizeof (struct pfm_manager_flash)); status = pfm_manager_init (&manager->base, &state->base, hash, port); if (status != 0) { return status; } status = manifest_manager_flash_init (&manager->manifest_manager, &state->flash_state, &manager->base.base, &pfm_region1->base.base, &pfm_region2->base.base, &pfm_region1->base_flash, &pfm_region2->base_flash, &state_mgr->base, hash, verification, 0, MANIFEST_LOGGING_EMPTY_PFM, false); if (status != 0) { goto manifest_base_error; } manager->base.get_active_pfm = pfm_manager_flash_get_active_pfm; manager->base.get_pending_pfm = pfm_manager_flash_get_pending_pfm; manager->base.free_pfm = pfm_manager_flash_free_pfm; manager->base.base.activate_pending_manifest = pfm_manager_flash_activate_pending_manifest; manager->base.base.clear_pending_region = pfm_manager_flash_clear_pending_region; manager->base.base.write_pending_data = pfm_manager_flash_write_pending_data; manager->base.base.verify_pending_manifest = pfm_manager_flash_verify_pending_manifest; manager->base.base.clear_all_manifests = pfm_manager_flash_clear_all_manifests; manager->host_state = state_mgr; return 0; manifest_base_error: pfm_manager_release (&manager->base); return status; } /** * Initialize only the variable state for a manager of PFMs on flash. The rest of the manager is * assumed to have already been initialized. * * This would generally be used with a statically initialized instance. * * @param manager The manager that contains the state to initialize. * * @return 0 if the state was successfully initialized or an error code. */ int pfm_manager_flash_init_state (const struct pfm_manager_flash *manager) { int status; if ((manager == NULL) || (manager->host_state == NULL)) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } status = pfm_manager_init_state (&manager->base); if (status != 0) { return status; } status = manifest_manager_flash_init_state (&manager->manifest_manager, MANIFEST_LOGGING_EMPTY_PFM); if (status != 0) { pfm_manager_release (&manager->base); } return status; } /** * Release the resources used by a manager of PFMs in flash. * * @param manager The PFM manager to release. */ void pfm_manager_flash_release (const struct pfm_manager_flash *manager) { if (manager != NULL) { pfm_manager_release (&manager->base); manifest_manager_flash_release (&manager->manifest_manager); } }