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