core/manifest/pcd/pcd_manager_flash.c (150 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 "pcd_manager_flash.h" #include "manifest/manifest_logging.h" #include "system/system_state_manager.h" /** * Get the PCD 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 PCD instance or null if there was an error. */ static const struct pcd* pcd_manager_flash_get_pcd (const struct pcd_manager_flash *manager, bool active) { const struct pcd_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 pcd_flash*) region->manifest; return &flash->base; } const struct pcd* pcd_manager_flash_get_active_pcd (const struct pcd_manager *manager) { const struct pcd_manager_flash *pcd_mgr = (const struct pcd_manager_flash*) manager; return pcd_manager_flash_get_pcd (pcd_mgr, true); } void pcd_manager_flash_free_pcd (const struct pcd_manager *manager, const struct pcd *pcd) { const struct pcd_manager_flash *pcd_mgr = (const struct pcd_manager_flash*) manager; if (pcd_mgr == NULL) { return; } manifest_manager_flash_free_manifest (&pcd_mgr->manifest_manager, (const struct manifest*) pcd); } int pcd_manager_flash_activate_pending_manifest (const struct manifest_manager *manager) { const struct pcd_manager_flash *pcd_mgr = (const struct pcd_manager_flash*) manager; int status; if (pcd_mgr == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } status = manifest_manager_flash_activate_pending_manifest (&pcd_mgr->manifest_manager); if (status == 0) { pcd_manager_on_pcd_activated (&pcd_mgr->base); } pcd_manager_on_pcd_activation_request (&pcd_mgr->base); return status; } int pcd_manager_flash_clear_pending_region (const struct manifest_manager *manager, size_t size) { const struct pcd_manager_flash *pcd_mgr = (const struct pcd_manager_flash*) manager; if (pcd_mgr == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } return manifest_manager_flash_clear_pending_region (&pcd_mgr->manifest_manager, size); } int pcd_manager_flash_write_pending_data (const struct manifest_manager *manager, const uint8_t *data, size_t length) { const struct pcd_manager_flash *pcd_mgr = (const struct pcd_manager_flash*) manager; if (pcd_mgr == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } return manifest_manager_flash_write_pending_data (&pcd_mgr->manifest_manager, data, length); } int pcd_manager_flash_verify_pending_manifest (const struct manifest_manager *manager) { const struct pcd_manager_flash *pcd_mgr = (const struct pcd_manager_flash*) manager; int status; if (pcd_mgr == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } status = manifest_manager_flash_verify_pending_manifest (&pcd_mgr->manifest_manager); if (status == 0) { pcd_manager_on_pcd_verified (&pcd_mgr->base, pcd_manager_flash_get_pcd (pcd_mgr, false)); } return status; } int pcd_manager_flash_clear_all_manifests (const struct manifest_manager *manager) { const struct pcd_manager_flash *pcd_mgr = (const struct pcd_manager_flash*) manager; int status; if (pcd_mgr == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } status = manifest_manager_flash_clear_all_manifests (&pcd_mgr->manifest_manager, false); if (status == 0) { pcd_manager_on_clear_active (&pcd_mgr->base); } return status; } /** * Initialize the manager for handling PCDs. * * @param manager The PCD manager to initialize. * @param state Variable context for the PCD manager. This must be uninitialized. * @param pcd_region1 The PCD instance for the first flash region that can hold a PCD. This region * does not need to have a valid PCD.The region is expected to a single flash erase block as * defined by FLASH_BLOCK_SIZE, aligned to the beginning of the block. * @param pcd_region2 The PCD instance for the second flash region that can hold a PCD. This region * does not need to have a valid PCD. 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 The state information for PCD management. * @param hash The hash engine to be used for PCD validation. * @param verification The module to be used for PCD verification. * * @return 0 if the PCD manager was successfully initialized or an error code. */ int pcd_manager_flash_init (struct pcd_manager_flash *manager, struct pcd_manager_flash_state *state, const struct pcd_flash *pcd_region1, const struct pcd_flash *pcd_region2, struct state_manager *state_mgr, const struct hash_engine *hash, const struct signature_verification *verification) { int status; if ((manager == NULL) || (state == NULL) || (pcd_region1 == NULL) || (pcd_region2 == NULL) || (state_mgr == NULL)) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } memset (manager, 0, sizeof (struct pcd_manager_flash)); status = pcd_manager_init (&manager->base, &state->base, hash); if (status != 0) { return status; } status = manifest_manager_flash_init (&manager->manifest_manager, &state->flash_state, &manager->base.base, &pcd_region1->base.base, &pcd_region2->base.base, &pcd_region1->base_flash, &pcd_region2->base_flash, state_mgr, hash, verification, SYSTEM_STATE_MANIFEST_PCD, MANIFEST_LOGGING_EMPTY_PCD, true); if (status != 0) { pcd_manager_release (&manager->base); return status; } manager->base.get_active_pcd = pcd_manager_flash_get_active_pcd; manager->base.free_pcd = pcd_manager_flash_free_pcd; manager->base.base.activate_pending_manifest = pcd_manager_flash_activate_pending_manifest; manager->base.base.clear_pending_region = pcd_manager_flash_clear_pending_region; manager->base.base.write_pending_data = pcd_manager_flash_write_pending_data; manager->base.base.verify_pending_manifest = pcd_manager_flash_verify_pending_manifest; manager->base.base.clear_all_manifests = pcd_manager_flash_clear_all_manifests; pcd_manager_flash_activate_pending_manifest (&manager->base.base); return 0; } /** * Initialize only the variable state for a manager of PCDs 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 pcd_manager_flash_init_state (const struct pcd_manager_flash *manager) { int status; if (manager == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } status = pcd_manager_init_state (&manager->base); if (status != 0) { return status; } status = manifest_manager_flash_init_state (&manager->manifest_manager, MANIFEST_LOGGING_EMPTY_PCD); if (status != 0) { pcd_manager_release (&manager->base); return status; } pcd_manager_flash_activate_pending_manifest (&manager->base.base); return 0; } /** * Release the resources used by a manager of PCDs in flash. * * @param manager The PCD manager to release. */ void pcd_manager_flash_release (const struct pcd_manager_flash *manager) { if (manager != NULL) { pcd_manager_release (&manager->base); manifest_manager_flash_release (&manager->manifest_manager); } }