Tool: Generate static handle for stateless service

Parsing from partition manifest and generate static handle
value for stateless services.

- Validate number of stateless services
- Static handle value auto allocation
- Duplicate detection

Change-Id: I8fdf79f5040caf1cbbdf42e52a4a405b36d88166
Signed-off-by: Mingyang Sun <mingyang.sun@arm.com>
diff --git a/tools/tfm_parse_manifest_list.py b/tools/tfm_parse_manifest_list.py
index 8bb1f25..d4a0d80 100644
--- a/tools/tfm_parse_manifest_list.py
+++ b/tools/tfm_parse_manifest_list.py
@@ -175,6 +175,71 @@
 
     print ("Generation of files done")
 
+def process_stateless_services(partitions, static_handle_max_num):
+    """
+    This function collects all stateless services together, and allocates
+    stateless handle for them.
+    If the stateless handle is set to a valid value in yaml file, it is used as
+    the index directly, if the stateless handle is set as "auto" or not set,
+    framework will allocate a valid index for the service.
+    After that, framework puts each service into a stateless service list at
+    position of its "index". Other elements in list are left None.
+    """
+    stateless_services = []
+
+    # Collect all stateless services first.
+    for partition in partitions:
+        # Skip the FF-M 1.0 partitions
+        if partition['manifest']['psa_framework_version'] < 1.1:
+            continue
+        # Skip the Non-IPC partitions
+        if partition['attr']['tfm_partition_ipc'] is not True:
+            continue
+        for service in partition['manifest']['services']:
+            if 'connection_based' not in service:
+                raise Exception("'connection_based' is mandatory in FF-M 1.1 service!")
+            if service['connection_based'] is False:
+                stateless_services.append(service)
+
+    if len(stateless_services) == 0:
+        return []
+
+    if len(stateless_services) > static_handle_max_num:
+        raise Exception("Stateless service numbers range exceed.")
+
+    """
+    Allocate an empty stateless service list to store services and find the
+    service easily by handle.
+    Use service stateless handle values as indexes. Put service in the list
+    at index "handle - 1", since handle value starts from 1 and list index
+    starts from 0.
+    """
+    reordered_stateless_list = [None] * static_handle_max_num
+
+    # Fill in services with specified stateless handle, index is "handle - 1".
+    for service in stateless_services:
+        if service['stateless_handle'] == "auto":
+            continue
+        try:
+            if reordered_stateless_list[service['stateless_handle']-1] is not None:
+                raise Exception("Duplicated stateless service handle.")
+            reordered_stateless_list[service['stateless_handle']-1] = service
+        except IndexError:
+            raise Exception("Stateless service index out of range.")
+        # Remove recorded node from the existing list
+        stateless_services.remove(service)
+
+    # Auto-allocate stateless handle
+    for i in range(0, static_handle_max_num):
+        if reordered_stateless_list[i] == None:
+            service = stateless_services.pop(0)
+            service['stateless_handle'] = i + 1
+            reordered_stateless_list[i] = service
+        if len(stateless_services) == 0:
+            break
+
+    return reordered_stateless_list
+
 def parse_args():
     parser = argparse.ArgumentParser(description='Parse secure partition manifest list and generate files listed by the file list',
                                      epilog='Note that environment variables in template files will be replaced with their values')
@@ -251,10 +316,11 @@
     utilities = {}
     context = {}
 
-    utilities['donotedit_warning']=donotedit_warning
+    utilities['donotedit_warning'] = donotedit_warning
 
     context['partitions'] = partition_db
     context['utilities'] = utilities
+    context['stateless_services'] = process_stateless_services(partition_db, 32)
 
     gen_files(context, gen_file_list)