J-Alves | 3cd7904 | 2022-03-21 14:08:27 +0000 | [diff] [blame] | 1 | #!/usr/bin/python3 |
| 2 | # Copyright (c) 2022, Arm Limited. All rights reserved. |
| 3 | # |
| 4 | # SPDX-License-Identifier: BSD-3-Clause |
| 5 | ''' |
| 6 | This is a python module for defining and executing SP setup actions, targeting |
| 7 | a system deploying an SPM implementation. |
| 8 | Each action consists of a function, that processes the SP layout json file and |
| 9 | other provided arguments. |
| 10 | At the core of this is the SpSetupActions which provides a means to register |
| 11 | the functions into a table of actions, and execute them all when invoking |
| 12 | SpSetupActions.run_actions. |
| 13 | Registering the function is done by using the decorator '@SpSetupActions.sp_action' |
| 14 | at function definition. |
| 15 | |
| 16 | Functions 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. |
| 19 | More information in the doc comments below. |
| 20 | ''' |
| 21 | import bisect |
| 22 | |
| 23 | DEFAULT_ACTION_ORDER = 100 |
| 24 | |
| 25 | class _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 | |
| 58 | class 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 | |
| 108 | if __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) |