Tool: Detect circular dependency in Secure Partitions
Circular dependencies between Secure Partitions are forbidden in FF-M.
For example, Partition A depends on service of Partition B,
while Partition B depends on Service A1 in Partition A.
That is a circular in partition dependency which is invalid.
This patch adds detection on this kind of circular when processing
partition manifests.
Signed-off-by: Xinyu Zhang <xinyu.zhang@arm.com>
Change-Id: I7d3e7b5636c9463e96686e57019af0fb85181d1f
diff --git a/tools/tfm_parse_manifest_list.py b/tools/tfm_parse_manifest_list.py
index a66b210..d37d9a8 100644
--- a/tools/tfm_parse_manifest_list.py
+++ b/tools/tfm_parse_manifest_list.py
@@ -153,9 +153,63 @@
return manifest
+def check_circular_dependency(partitions, service_partition_map):
+ """
+ This function detects if there is any circular partition dependency chain.
+ If a circular dependency is detected, the script exits with error.
+
+ Inputs:
+ - partitions: dict of partition manifests
+ - service_partition_map: map between services and their owner Partitions
+ """
+
+ dependency_table = {}
+ for partition in partitions:
+ manifest = partition['manifest']
+ dependencies = manifest['dependencies'].copy() \
+ if 'dependencies' in manifest else []
+ dependencies += manifest['weak_dependencies'].copy() \
+ if 'weak_dependencies' in manifest else []
+ dependency_table[manifest['name']] = {
+ 'dependencies': [service_partition_map[dependency]
+ for dependency in dependencies
+ if dependency in service_partition_map],
+ 'validated': False
+ }
+
+ for partition in dependency_table.keys():
+ validate_dependency_chain(partition, dependency_table, [])
+
+def validate_dependency_chain(partition,
+ dependency_table,
+ dependency_chain):
+ """
+ Recursively validate if the given partition and its dependencies
+ have a circular dependency with the given dependency_chain.
+ Exit with error code once any circular is detected.
+
+ Inputs:
+ - partition: next partition to be checked
+ - dependency_table: dict of partitions and their dependencies
+ - dependency_chain: list of dependencies in current chain
+ """
+
+ dependency_chain.append(partition)
+ if partition in dependency_chain[:-1]:
+ logging.error(
+ 'Circular dependency exists in chain: {}'.format(
+ ', '.join(dependency_chain)))
+ exit(1)
+ for dependency in dependency_table[partition]['dependencies']:
+ if dependency_table[dependency]['validated']:
+ continue
+ validate_dependency_chain(dependency, dependency_table, dependency_chain)
+ dependency_table[partition]['validated'] = True
+
def process_partition_manifests(manifest_lists, isolation_level, backend):
"""
- Parse the input manifest lists, generate the data base for genereated files
+ Parse the input manifest lists, check if manifest settings are valid,
+ generate the data base for genereated files
and generate manifest header files.
Parameters
@@ -178,6 +232,7 @@
all_manifests = []
pid_list = []
no_pid_manifest_idx = []
+ service_partition_map = {}
partition_statistics = {
'connection_based_srv_num': 0,
'ipc_partitions': [],
@@ -274,6 +329,7 @@
# number (0) when there are no services.
srv_idx = -1
for srv_idx, service in enumerate(manifest.get('services', [])):
+ service_partition_map[service['name']] = manifest['name']
if manifest['model'] == 'IPC':
# Assign signal value, the first 4 bits are reserved by FF-M
service['signal_value'] = (1 << (srv_idx + 4))
@@ -326,6 +382,8 @@
'loadinfo_file': load_info_file,
'output_dir':output_dir})
+ check_circular_dependency(partition_list, service_partition_map)
+
# Automatically assign PIDs for partitions without 'pid' attribute
pid = max(pid_list, default = TFM_PID_BASE - 1)
for idx in no_pid_manifest_idx: