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