TF-RMM Release v0.1.0

This is the first external release of TF-RMM and provides a reference
implementation of Realm Management Monitor (RMM) as specified by the
RMM Beta0 specification[1].

The `docs/readme.rst` has more details about the project and
`docs/getting_started/getting-started.rst` has details on how to get
started with TF-RMM.

[1] https://developer.arm.com/documentation/den0137/1-0bet0/?lang=en

Signed-off-by: Soby Mathew <soby.mathew@arm.com>
Change-Id: I205ef14c015e4a37ae9ae1a64e4cd22eb8da746e
diff --git a/tools/checkincludes/checkincludes.py b/tools/checkincludes/checkincludes.py
new file mode 100755
index 0000000..a18605a
--- /dev/null
+++ b/tools/checkincludes/checkincludes.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+# SPDX-FileCopyrightText: Copyright Arm Limited and Contributors.
+#
+
+from argparse import ArgumentParser
+import codecs
+import os
+import re
+import sys
+import logging
+from os import access, R_OK
+from os.path import isfile
+
+INCLUDE_RE = re.compile(r"^\s*#\s*include\s\s*(?P<path>[\"<].+[\">])")
+
+# exit program with rc
+def print_error_and_exit(total_errors):
+    if total_errors:
+        print("total: " + str(total_errors) + " errors")
+        sys.exit(1)
+    else:
+        sys.exit(0)
+
+def include_paths(lines):
+    """List all include paths in a file. Ignore starting `+` in diff mode."""
+    pattern = INCLUDE_RE
+    matches = (pattern.match(line) for line in lines)
+    return [m.group("path") for m in matches if m]
+
+# check if 'file' is a regular file and it is readable
+def file_readable(file):
+    if not isfile(file):
+        print(file + ": WARNING: File not found")
+        return 0
+
+    if not access(file, R_OK):
+        print(file + ": WARNING: File not readable")
+        return 0
+
+    return 1
+
+def file_include_list(path):
+    """Return a list of all include paths in a file or None on failure."""
+    try:
+        with codecs.open(path, encoding="utf-8") as f:
+            return include_paths(f)
+    except Exception:
+        logging.exception(path + ": ERROR while parsing.")
+        return ([])
+
+def check_includes(file):
+    """Checks whether the order of includes in the file specified in the path
+    is correct or not."""
+    print("Checking file: " + file)
+    if not file_readable(file):
+        return 0
+
+    inc_list = file_include_list(file)
+
+    # If there are less than 2 includes there's no need to check.
+    if len(inc_list) < 2:
+        return 0
+
+    # remove leading and trailing <, >
+    inc_list = [x[1:-1] for x in inc_list]
+
+    if sorted(inc_list) != inc_list:
+        print(file + ": ERROR: includes not in order. Include order should be " +
+              ', '.join(sorted(inc_list)))
+        return 1
+    else:
+        return 0
+
+if __name__ == "__main__":
+    ap = ArgumentParser(description='Check #include orders')
+    ap.add_argument('files', nargs='*', help='Check files.')
+    args = ap.parse_args()
+
+    total_errors = 0
+    for file in args.files:
+        total_errors += check_includes(file)
+
+    print_error_and_exit(total_errors)