Add installer factory
Adds an interface for constructing installers. Allows for alternative
sets of installers to be used on different platforms. At the moment,
supported installers are general purpose. It is anticipated that
domain specific installers will be needed with image format specific
knowledge.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I359561a8d908bac5ba826ad38ba27291a4f06f2d
diff --git a/components/service/fwu/installer/factory/default/component.cmake b/components/service/fwu/installer/factory/default/component.cmake
new file mode 100644
index 0000000..7cb6634
--- /dev/null
+++ b/components/service/fwu/installer/factory/default/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/installer_factory.c"
+ )
diff --git a/components/service/fwu/installer/factory/default/installer_factory.c b/components/service/fwu/installer/factory/default/installer_factory.c
new file mode 100644
index 0000000..96eec26
--- /dev/null
+++ b/components/service/fwu/installer/factory/default/installer_factory.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <common/uuid/uuid.h>
+#include <service/fwu/installer/installer.h>
+#include <service/fwu/installer/factory/locations.h>
+#include <service/fwu/installer/factory/installer_factory.h>
+#include <service/fwu/installer/copy/copy_installer.h>
+#include <service/fwu/installer/raw/raw_installer.h>
+
+/**
+ * An installer factory for constructing installers for a platform
+ * that conforms to the following constraints:
+ *
+ * 1. AP firmware is contained within a FIP that resides within a separate
+ * storage volume (* n banks). A volume will normally map to a flash partition.
+ * 2. SCP firmware, if present, is always updated as a single unit and resides in
+ * a separate storage volume.
+ * 3. RSS firmware, if present, is always updated as a single unit and resides in
+ * a separate storage volume.
+ */
+
+static bool check_supported_locations(
+ const char *supported_uuids[],
+ const struct uuid_octets *location_uuid)
+{
+ bool is_supported = false;
+ unsigned int i = 0;
+
+ while (supported_uuids[i]) {
+
+ struct uuid_octets comparison_uuid;
+
+ uuid_guid_octets_from_canonical(&comparison_uuid, supported_uuids[i]);
+
+ if (uuid_is_equal(comparison_uuid.octets, location_uuid->octets)) {
+
+ is_supported = true;
+ break;
+ }
+
+ ++i;
+ }
+
+ return is_supported;
+}
+
+struct installer *installer_factory_create_installer(
+ enum install_type installation_type,
+ unsigned int location_id,
+ const struct uuid_octets *location_uuid)
+{
+ assert(location_uuid);
+
+ struct installer *product = NULL;
+
+ if (installation_type == INSTALL_TYPE_WHOLE_VOLUME) {
+
+#ifdef RAW_INSTALLER_AVAILABLE
+ static const char *raw_installer_compatibility[] = {
+ LOCATION_UUID_AP_FW,
+ LOCATION_UUID_SCP_FW,
+ LOCATION_UUID_RSS_FW,
+ NULL
+ };
+
+ if (check_supported_locations(raw_installer_compatibility, location_uuid)) {
+
+ struct raw_installer *raw_installer =
+ (struct raw_installer *)malloc(sizeof(struct raw_installer));
+
+ if (raw_installer) {
+
+ raw_installer_init(raw_installer, location_uuid, location_id);
+ product = &raw_installer->base_installer;
+ }
+ }
+#endif
+
+ } else if (installation_type == INSTALL_TYPE_WHOLE_VOLUME_COPY) {
+
+#ifdef COPY_INSTALLER_AVAILABLE
+ static const char *copy_installer_compatibility[] = {
+ LOCATION_UUID_AP_FW,
+ LOCATION_UUID_SCP_FW,
+ LOCATION_UUID_RSS_FW,
+ NULL
+ };
+
+ if (check_supported_locations(copy_installer_compatibility, location_uuid)) {
+
+ struct copy_installer *copy_installer =
+ (struct copy_installer *)malloc(sizeof(struct copy_installer));
+
+ if (copy_installer) {
+
+ copy_installer_init(copy_installer, location_uuid, location_id);
+ product = ©_installer->base_installer;
+ }
+ }
+#endif
+ }
+
+ return product;
+}
+
+void installer_factory_destroy_installer(
+ struct installer *installer)
+{
+ if (installer)
+ free(installer->context);
+}
diff --git a/components/service/fwu/installer/factory/default/test/component.cmake b/components/service/fwu/installer/factory/default/test/component.cmake
new file mode 100644
index 0000000..b9da3aa
--- /dev/null
+++ b/components/service/fwu/installer/factory/default/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/default_installer_factory_tests.cpp"
+ )
diff --git a/components/service/fwu/installer/factory/default/test/default_installer_factory_tests.cpp b/components/service/fwu/installer/factory/default/test/default_installer_factory_tests.cpp
new file mode 100644
index 0000000..9a71426
--- /dev/null
+++ b/components/service/fwu/installer/factory/default/test/default_installer_factory_tests.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/uuid/uuid.h>
+#include <media/disk/guid.h>
+#include <service/fwu/installer/factory/locations.h>
+#include <service/fwu/installer/factory/installer_factory.h>
+#include <service/fwu/installer/installer_index.h>
+#include <CppUTest/TestHarness.h>
+
+TEST_GROUP(FwuDefaultInstallerFactoryTests)
+{
+ void setup()
+ {
+ installer_index_init();
+ }
+
+ void teardown()
+ {
+ unsigned int i = 0;
+
+ do {
+
+ struct installer *installer = installer_index_get(i);
+
+ if (!installer)
+ break;
+
+ installer_factory_destroy_installer(installer);
+ ++i;
+
+ } while (1);
+
+ installer_index_clear();
+ }
+};
+
+TEST(FwuDefaultInstallerFactoryTests, configureInstallersFlow)
+{
+ struct uuid_octets ap_fw_uuid;
+ struct uuid_octets scp_fw_uuid;
+ struct uuid_octets rss_fw_uuid;
+
+ /* Check configuration operations that will be performed when
+ * constructing a set of installers for a platform. The platform
+ * consists of multiple firmware locations. This sequence
+ * represents the configuration steps performed when iterating
+ * over a GPT to identify updatable partitions.
+ */
+
+ /* Configure installers for updating AP firmware */
+ uuid_guid_octets_from_canonical(&ap_fw_uuid,LOCATION_UUID_AP_FW);
+
+ /* Expect no installer to initially be registered */
+ CHECK_FALSE(installer_index_find_by_location_uuid(&ap_fw_uuid));
+
+ /* Configure for whole volume and copy installation */
+ struct installer *installer = installer_factory_create_installer(
+ INSTALL_TYPE_WHOLE_VOLUME, 0, &ap_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&ap_fw_uuid));
+
+ installer = installer_factory_create_installer(
+ INSTALL_TYPE_WHOLE_VOLUME_COPY, 0, &ap_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&ap_fw_uuid));
+
+ /* Configure installers for updating SCP firmware */
+ uuid_guid_octets_from_canonical(&scp_fw_uuid,LOCATION_UUID_SCP_FW);
+
+ /* Expect no installer to initially be registered */
+ CHECK_FALSE(installer_index_find_by_location_uuid(&scp_fw_uuid));
+
+ /* Configure for whole volume and copy installation */
+ installer = installer_factory_create_installer(
+ INSTALL_TYPE_WHOLE_VOLUME, 0, &scp_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&scp_fw_uuid));
+
+ installer = installer_factory_create_installer(
+ INSTALL_TYPE_WHOLE_VOLUME_COPY, 0, &scp_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&scp_fw_uuid));
+
+ /* Configure installers for updating RSS firmware */
+ uuid_guid_octets_from_canonical(&rss_fw_uuid,LOCATION_UUID_RSS_FW);
+
+ /* Expect no installer to initially be registered */
+ CHECK_FALSE(installer_index_find_by_location_uuid(&rss_fw_uuid));
+
+ /* Configure for whole volume and copy installation */
+ installer = installer_factory_create_installer(
+ INSTALL_TYPE_WHOLE_VOLUME, 0, &rss_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&rss_fw_uuid));
+
+ installer = installer_factory_create_installer(
+ INSTALL_TYPE_WHOLE_VOLUME_COPY, 0, &rss_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&rss_fw_uuid));
+
+ /* Now try and construct an installer for an unsupported partition type. */
+ struct uuid_octets unsupported_location_uuid;
+
+ uuid_guid_octets_from_canonical(&unsupported_location_uuid,
+ DISK_GUID_PARTITION_TYPE_FWU_METADATA);
+
+ installer = installer_factory_create_installer(INSTALL_TYPE_WHOLE_VOLUME,
+ 0, &unsupported_location_uuid);
+ CHECK_FALSE(installer);
+
+ CHECK_FALSE(installer_index_find_by_location_uuid(&unsupported_location_uuid));
+}
diff --git a/components/service/fwu/installer/factory/installer_factory.h b/components/service/fwu/installer/factory/installer_factory.h
new file mode 100644
index 0000000..7bf80c1
--- /dev/null
+++ b/components/service/fwu/installer/factory/installer_factory.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INSTALLER_FACTORY_H
+#define INSTALLER_FACTORY_H
+
+#include <common/uuid/uuid.h>
+#include <service/fwu/agent/install_type.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct installer;
+
+/**
+ * \brief An interface for constructing image installers
+ *
+ * The FWU update service can be used to install a diverse range of firmware images. To
+ * allow for platform specific installers that handle different image formats and installation
+ * methods, a common interface is used for constructing concrete installers. The implementation
+ * of the installer_factory determines the set of concrete installers that are available
+ * in a deployment. It is envisaged that alternative factory implementations will be needed
+ * to cater for different classes of product with different installation requirements. A
+ * constructed installer should be destroyed using the installer_factory_destroy_installer
+ * method when the installer is no longer needed.
+ *
+ * \param[in] installation_type The type of installation required
+ * \param[in] location_id The short location_id that corresponds to the location_uuid
+ * \param[in] location_uuid UUID to identify the location into which images will be installed
+ *
+ * \return The constructed installer or NULL if no suitable installer can be constructed.
+ */
+struct installer *installer_factory_create_installer(
+ enum install_type installation_type,
+ unsigned int location_id,
+ const struct uuid_octets *location_uuid);
+
+/**
+ * \brief Destroy an installer
+ *
+ * \param[in] installer Installer to destroy
+ */
+void installer_factory_destroy_installer(
+ struct installer *installer);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INSTALLER_FACTORY_H */
diff --git a/components/service/fwu/installer/factory/locations.h b/components/service/fwu/installer/factory/locations.h
new file mode 100644
index 0000000..a20a7bc
--- /dev/null
+++ b/components/service/fwu/installer/factory/locations.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INSTALLER_FACTORY_LOCATIONS_H
+#define INSTALLER_FACTORY_LOCATIONS_H
+
+/**
+ * Locations represent updatable firmware subsystems. Installers target
+ * locations for image installation purposes. A location is identified
+ * by a UUID. Where firmware images are stored within GPT formatted
+ * storage, a location UUID is used as the partition type GUID. For
+ * example, the A and B partitions holding application processor
+ * firmware will both be labelled with the same partition type GUID.
+ * The following UUIDs identify locations used by concrete installer
+ * factories as a qualifier for rules that define which installers
+ * are needed to update particular locations. New location UUIDs may
+ * be freely added to this file.
+ */
+
+/* Location UUID for application processor firmware */
+#define LOCATION_UUID_AP_FW \
+ "2451cd6e-90fe-4b15-bf10-a69bce2d4486"
+
+/* Location UUID for SCP firmware */
+#define LOCATION_UUID_SCP_FW \
+ "691d5ea3-27fe-4104-badd-7539c00a9095"
+
+/* Location UUID for RSS firmware */
+#define LOCATION_UUID_RSS_FW \
+ "c948a156-58cb-4c38-b406-e60bff2223d5"
+
+#endif /* INSTALLER_FACTORY_LOCATIONS_H */
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index 13077f1..cf43cf7 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -117,6 +117,8 @@
"components/service/fwu/installer/raw/test"
"components/service/fwu/installer/copy"
"components/service/fwu/installer/copy/test"
+ "components/service/fwu/installer/factory/default"
+ "components/service/fwu/installer/factory/default/test"
"components/service/fwu/inspector/mock"
"components/service/crypto/client/cpp"
"components/service/crypto/client/cpp/protocol/protobuf"