xref: /arm-trusted-firmware/tools/sptool/spactions.py (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu#!/usr/bin/python3
2*91f16700Schasinglulu# Copyright (c) 2022, Arm Limited. All rights reserved.
3*91f16700Schasinglulu#
4*91f16700Schasinglulu# SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu'''
6*91f16700SchasingluluThis is a python module for defining and executing SP setup actions, targeting
7*91f16700Schasinglulua system deploying an SPM implementation.
8*91f16700SchasingluluEach action consists of a function, that processes the SP layout json file and
9*91f16700Schasingluluother provided arguments.
10*91f16700SchasingluluAt the core of this is the SpSetupActions which provides a means to register
11*91f16700Schasingluluthe functions into a table of actions, and execute them all when invoking
12*91f16700SchasingluluSpSetupActions.run_actions.
13*91f16700SchasingluluRegistering the function is done by using the decorator '@SpSetupActions.sp_action'
14*91f16700Schasingluluat function definition.
15*91f16700Schasinglulu
16*91f16700SchasingluluFunctions can be called:
17*91f16700Schasinglulu- once only, or per SP defined in the SP layout file;
18*91f16700Schasinglulu- following an order, from lowest to highest of their execution order.
19*91f16700SchasingluluMore information in the doc comments below.
20*91f16700Schasinglulu'''
21*91f16700Schasingluluimport bisect
22*91f16700Schasinglulu
23*91f16700SchasingluluDEFAULT_ACTION_ORDER = 100
24*91f16700Schasinglulu
25*91f16700Schasingluluclass _ConfiguredAction:
26*91f16700Schasinglulu    """
27*91f16700Schasinglulu    Wraps action function with its configuration.
28*91f16700Schasinglulu    """
29*91f16700Schasinglulu    def __init__(self, action, exec_order=DEFAULT_ACTION_ORDER, global_action=True, log_calls = False):
30*91f16700Schasinglulu        self.exec_order = exec_order
31*91f16700Schasinglulu        self.__name__ = action.__name__
32*91f16700Schasinglulu        def logged_action(action):
33*91f16700Schasinglulu            def inner_logged_action(sp_layout, sp, args :dict):
34*91f16700Schasinglulu                print(f"Calling {action.__name__} -> {sp}")
35*91f16700Schasinglulu                return action(sp_layout, sp, args)
36*91f16700Schasinglulu            return inner_logged_action
37*91f16700Schasinglulu        self.action = logged_action(action) if log_calls is True else action
38*91f16700Schasinglulu        self.global_action = global_action
39*91f16700Schasinglulu
40*91f16700Schasinglulu    def __lt__(self, other):
41*91f16700Schasinglulu        """
42*91f16700Schasinglulu        To allow for ordered inserts in a list of actions.
43*91f16700Schasinglulu        """
44*91f16700Schasinglulu        return self.exec_order < other.exec_order
45*91f16700Schasinglulu
46*91f16700Schasinglulu    def __call__(self, sp_layout, sp, args :dict):
47*91f16700Schasinglulu        """
48*91f16700Schasinglulu        Calls action function.
49*91f16700Schasinglulu        """
50*91f16700Schasinglulu        return self.action(sp_layout, sp, args)
51*91f16700Schasinglulu
52*91f16700Schasinglulu    def __repr__(self) -> str:
53*91f16700Schasinglulu        """
54*91f16700Schasinglulu        Pretty format to show debug information about the action.
55*91f16700Schasinglulu        """
56*91f16700Schasinglulu        return f"func: {self.__name__}; global:{self.global_action}; exec_order: {self.exec_order}"
57*91f16700Schasinglulu
58*91f16700Schasingluluclass SpSetupActions:
59*91f16700Schasinglulu    actions = []
60*91f16700Schasinglulu
61*91f16700Schasinglulu    def sp_action(in_action = None, global_action = False, log_calls=False, exec_order=DEFAULT_ACTION_ORDER):
62*91f16700Schasinglulu        """
63*91f16700Schasinglulu        Function decorator that registers and configures action.
64*91f16700Schasinglulu
65*91f16700Schasinglulu        :param in_action - function to register
66*91f16700Schasinglulu        :param global_action - make the function global, i.e. make it be
67*91f16700Schasinglulu        only called once.
68*91f16700Schasinglulu        :param log_calls - at every call to action, a useful log will be printed.
69*91f16700Schasinglulu        :param exec_order - action's calling order.
70*91f16700Schasinglulu        """
71*91f16700Schasinglulu        def append_action(action):
72*91f16700Schasinglulu            action = _ConfiguredAction(action, exec_order, global_action, log_calls)
73*91f16700Schasinglulu            bisect.insort(SpSetupActions.actions, action)
74*91f16700Schasinglulu            return action
75*91f16700Schasinglulu        if in_action is not None:
76*91f16700Schasinglulu            return append_action(in_action)
77*91f16700Schasinglulu        return append_action
78*91f16700Schasinglulu
79*91f16700Schasinglulu    def run_actions(sp_layout: dict, args: dict, verbose=False):
80*91f16700Schasinglulu        """
81*91f16700Schasinglulu        Executes all actions in accordance to their registering configuration:
82*91f16700Schasinglulu        - If set as "global" it will be called once.
83*91f16700Schasinglulu        - Actions are called respecting the order established by their "exec_order" field.
84*91f16700Schasinglulu
85*91f16700Schasinglulu        :param sp_layout - dictionary containing the SP layout information.
86*91f16700Schasinglulu        :param args - arguments to be propagated through the call of actions.
87*91f16700Schasinglulu        :param verbose - prints actions information in order of execution.
88*91f16700Schasinglulu        """
89*91f16700Schasinglulu        args["called"] = [] # for debug purposes
90*91f16700Schasinglulu        def append_called(action, sp, args :dict):
91*91f16700Schasinglulu            args["called"].append(f"{action.__name__} -> {sp}")
92*91f16700Schasinglulu            return args
93*91f16700Schasinglulu
94*91f16700Schasinglulu        for action in SpSetupActions.actions:
95*91f16700Schasinglulu            if verbose:
96*91f16700Schasinglulu                print(f"Calling {action}")
97*91f16700Schasinglulu            if action.global_action:
98*91f16700Schasinglulu                scope = "global"
99*91f16700Schasinglulu                args = action(sp_layout, scope, args)
100*91f16700Schasinglulu                args = append_called(action, scope, args)
101*91f16700Schasinglulu            else:
102*91f16700Schasinglulu                # Functions that are not global called for each SP defined in
103*91f16700Schasinglulu                # the SP layout.
104*91f16700Schasinglulu                for sp in sp_layout.keys():
105*91f16700Schasinglulu                    args = action(sp_layout, sp, args)
106*91f16700Schasinglulu                    args = append_called(action, sp, args)
107*91f16700Schasinglulu
108*91f16700Schasingluluif __name__ == "__main__":
109*91f16700Schasinglulu    # Executing this module will have the following test code/playground executed
110*91f16700Schasinglulu    sp_layout = {
111*91f16700Schasinglulu        "partition1" : {
112*91f16700Schasinglulu            "boot-info": True,
113*91f16700Schasinglulu            "image": {
114*91f16700Schasinglulu                "file": "partition.bin",
115*91f16700Schasinglulu                "offset":"0x2000"
116*91f16700Schasinglulu            },
117*91f16700Schasinglulu            "pm": {
118*91f16700Schasinglulu                "file": "cactus.dts",
119*91f16700Schasinglulu                "offset":"0x1000"
120*91f16700Schasinglulu            },
121*91f16700Schasinglulu            "owner": "SiP"
122*91f16700Schasinglulu        },
123*91f16700Schasinglulu        "partition2" : {
124*91f16700Schasinglulu            "image": "partition.bin",
125*91f16700Schasinglulu            "pm": "cactus-secondary.dts",
126*91f16700Schasinglulu            "owner": "Plat"
127*91f16700Schasinglulu        },
128*91f16700Schasinglulu        "partition3" : {
129*91f16700Schasinglulu            "image": "partition.bin",
130*91f16700Schasinglulu            "pm": "cactus-tertiary.dts",
131*91f16700Schasinglulu            "owner": "Plat"
132*91f16700Schasinglulu        },
133*91f16700Schasinglulu        "partition4" : {
134*91f16700Schasinglulu            "image": "ivy.bin",
135*91f16700Schasinglulu            "pm": "ivy.dts",
136*91f16700Schasinglulu            "owner": "Plat"
137*91f16700Schasinglulu        }
138*91f16700Schasinglulu    }
139*91f16700Schasinglulu
140*91f16700Schasinglulu    #Example of how to use this module
141*91f16700Schasinglulu    @SpSetupActions.sp_action(global_action=True)
142*91f16700Schasinglulu    def my_action1(sp_layout, _, args :dict):
143*91f16700Schasinglulu        print(f"inside function my_action1{sp_layout}\n\n args:{args})")
144*91f16700Schasinglulu        return args # Always return args in action function.
145*91f16700Schasinglulu    @SpSetupActions.sp_action(exec_order=1)
146*91f16700Schasinglulu    def my_action2(sp_layout, sp_name, args :dict):
147*91f16700Schasinglulu        print(f"inside function my_action2; SP: {sp_name} {sp_layout} args:{args}")
148*91f16700Schasinglulu        return args
149*91f16700Schasinglulu
150*91f16700Schasinglulu    # Example arguments to be propagated through the functions.
151*91f16700Schasinglulu    # 'args' can be extended in the action functions.
152*91f16700Schasinglulu    args = dict()
153*91f16700Schasinglulu    args["arg1"] = 0xEEE
154*91f16700Schasinglulu    args["arg2"] = 0xFF
155*91f16700Schasinglulu    SpSetupActions.run_actions(sp_layout, args)
156