irq_test: Add IRQ testing tool

Add python scripts for debuggers to test IRQ handling in TF-M.

Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
Change-Id: I6c5c0b920e3a0c38b3a0c867c93dd5851c66ff8b
diff --git a/irq_test_tool/irq_test_executor.py b/irq_test_tool/irq_test_executor.py
new file mode 100644
index 0000000..d98096f
--- /dev/null
+++ b/irq_test_tool/irq_test_executor.py
@@ -0,0 +1,180 @@
+#-------------------------------------------------------------------------------

+# Copyright (c) 2020, Arm Limited. All rights reserved.

+#

+# SPDX-License-Identifier: BSD-3-Clause

+#

+#-------------------------------------------------------------------------------

+

+from irq_test_abstract_debugger import Location

+import logging

+import json

+

+def create_locations_from_file(breakpoints_file_name):

+    """Internal function to create Location objects of a breakpoints data file

+    """

+    # Read in the points to break at

+    logging.info("Reading breakpoints file '%s'", breakpoints_file_name)

+    breakpoints_file = open(breakpoints_file_name)

+    breakpoints = json.load(breakpoints_file)

+    logging.debug("breakpoints: %s", str(breakpoints))

+

+    #TODO: go over the breakpoints and try to set them as a sanity check

+

+    locations = {}

+

+    for loc_name in breakpoints['breakpoints']:

+        bkpt = breakpoints['breakpoints'][loc_name]

+        offset = 0

+

+        if 'file' in bkpt:

+            filename = bkpt['file']

+        else:

+            filename = None

+

+        if 'symbol' in bkpt:

+            symbol = bkpt['symbol']

+            if 'offset' in bkpt:

+                offset = bkpt['offset']

+            else:

+                offset = 0

+        else:

+            if 'offset' in bkpt:

+                logging.error("In location %s offset is included without a"

+                              " symbol")

+                exit(2)

+            symbol = None

+

+        if 'line' in bkpt:

+            line = bkpt['line']

+            try:

+                int(line)

+            except ValueError:

+                logging.error("In location %s line is not a valid int",

+                              loc_name)

+                exit(2)

+        else:

+            line = None

+

+        if symbol:

+            if line or filename:

+                logging.error("In location %s nor filename nor line should"

+                              "be present when symbol is present", loc_name)

+                exit(2)

+

+        if (not line and filename) or (line and not filename):

+            logging.error("In location %s line and filename have to be "

+                          "present the same time", loc_name)

+            exit(2)

+

+        if (not symbol) and (not filename):

+            logging.error("In location %s no symbol nor code location is "

+                          "specified at all", loc_name)

+            exit(2)

+

+        loc = Location(symbol=symbol, offset=offset, filename=filename, line=line)

+

+        locations[loc_name] = loc

+

+    return locations

+

+class TestExecutor(object):

+    """ This class implements the test logic.

+

+    It reads the input files, and executes the steps of the testcase. It receives an

+    AbstractDebugger instance on creation. The test execution is implemented in the

+    execute function.

+    """

+

+    def __init__(self, debugger):

+        self.debugger = debugger

+

+    def execute(self, irqs_filename, breakpoints_filename, testcase_filename):

+        """ Execute a testcase

+

+        Execute the testcase defined in 'testcase_filename', using the IRQs and

+        breakpoints defined in irqs_filename and breakpoints_filename.

+        """

+        # Read in the list of IRQs

+        logging.info("Reading irqs file '%s'", irqs_filename)

+        irqs_file = open(irqs_filename)

+        irqs = json.load(irqs_file)

+        logging.debug("irqs: %s", str(irqs))

+

+        # read in the test sequence

+        logging.info("Reading test sequence file '%s'", testcase_filename)

+        test_file = open(testcase_filename)

+        test = json.load(test_file)

+        logging.debug("testcase: %s", str(test))

+

+        # TODO: crosscheck the tests file against the breakpoints and the irq's

+        #       available

+

+        locations = create_locations_from_file(breakpoints_filename)

+

+        self.debugger.clear_breakpoints()

+

+        # execute the test

+        steps = test['steps']

+        for i, step in enumerate(steps):

+

+            logging.info("---- Step %d ----", i)

+

+            continue_execution = False

+

+            if 'wait_for' in step:

+                bp_name = step['wait_for']

+                self.debugger.set_breakpoint(bp_name, locations[bp_name])

+                next_to_break_at = bp_name

+                continue_execution = True

+            elif 'expect' in step:

+                bp_name = step['expect']

+                self.debugger.set_breakpoint(bp_name, locations[bp_name])

+                next_to_break_at = bp_name

+

+                # Find the next wait_for in the test sequence, and set a

+                # breakpoint for that as well. So that it can be detected if an

+                # expected breakpoint is missed.

+

+                wait_for_found = False

+                ii = i+1

+

+                while ii < len(steps) and not wait_for_found:

+                    next_step = steps[ii]

+                    if 'wait_for' in next_step:

+                        next_bp_name = next_step['wait_for']

+                        self.debugger.set_breakpoint(next_bp_name,

+                                                     locations[next_bp_name])

+                        wait_for_found = True

+                    ii += 1

+

+                continue_execution = True

+

+

+            if 'trigger' in step:

+                irqs_dict = irqs['irqs']

+                irq = irqs_dict[step['trigger']]

+                line_nu = irq['line_num']

+                self.debugger.trigger_interrupt(line_nu)

+

+

+            if continue_execution:

+                self.debugger.continue_execution()

+

+                triggered_breakpoint = self.debugger.get_triggered_breakpoint()

+

+                if triggered_breakpoint is None:

+                    logging.error("No breakpoint was hit?????")

+                    exit(0)

+

+                if triggered_breakpoint != next_to_break_at:

+                    logging.error("execution stopped at '%s' instead of '%s'",

+                                triggered_breakpoint, next_to_break_at)

+                    exit(0)

+            else:

+                logging.error("execution stopped as no breakpoint is set")

+                exit(1)

+

+            self.debugger.clear_breakpoints()

+

+        logging.info("All the steps in the test file are executed successfully"

+                     " with the expected result.")