mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-08 05:43:53 +00:00

Developed python framework to help with SPs configuration. The framework allows for functions (dubbed "actions" in the framework) to be defined that should process the "sp_layout.json" file. Signed-off-by: J-Alves <joao.alves@arm.com> Change-Id: I278cd5a7aa0574168473e28f3b0fe231d7b548ee
155 lines
5.6 KiB
Python
155 lines
5.6 KiB
Python
#!/usr/bin/python3
|
|
# Copyright (c) 2022, Arm Limited. All rights reserved.
|
|
#
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
'''
|
|
This is a python module for defining and executing SP setup actions, targeting
|
|
a system deploying an SPM implementation.
|
|
Each action consists of a function, that processes the SP layout json file and
|
|
other provided arguments.
|
|
At the core of this is the SpSetupActions which provides a means to register
|
|
the functions into a table of actions, and execute them all when invoking
|
|
SpSetupActions.run_actions.
|
|
Registering the function is done by using the decorator '@SpSetupActions.sp_action'
|
|
at function definition.
|
|
|
|
Functions can be called:
|
|
- once only, or per SP defined in the SP layout file;
|
|
- following an order, from lowest to highest of their execution order.
|
|
More information in the doc comments below.
|
|
'''
|
|
import bisect
|
|
|
|
DEFAULT_ACTION_ORDER = 100
|
|
|
|
class _ConfiguredAction:
|
|
"""
|
|
Wraps action function with its configuration.
|
|
"""
|
|
def __init__(self, action, exec_order=DEFAULT_ACTION_ORDER, global_action=True, log_calls = False):
|
|
self.exec_order = exec_order
|
|
self.__name__ = action.__name__
|
|
def logged_action(action):
|
|
def inner_logged_action(sp_layout, sp, args :dict):
|
|
print(f"Calling {action.__name__} -> {sp}")
|
|
return action(sp_layout, sp, args)
|
|
return inner_logged_action
|
|
self.action = logged_action(action) if log_calls is True else action
|
|
self.global_action = global_action
|
|
|
|
def __lt__(self, other):
|
|
"""
|
|
To allow for ordered inserts in a list of actions.
|
|
"""
|
|
return self.exec_order < other.exec_order
|
|
|
|
def __call__(self, sp_layout, sp, args :dict):
|
|
"""
|
|
Calls action function.
|
|
"""
|
|
return self.action(sp_layout, sp, args)
|
|
|
|
def __repr__(self) -> str:
|
|
"""
|
|
Pretty format to show debug information about the action.
|
|
"""
|
|
return f"func: {self.__name__}; global:{self.global_action}; exec_order: {self.exec_order}"
|
|
|
|
class SpSetupActions:
|
|
actions = []
|
|
|
|
def sp_action(in_action = None, global_action = False, log_calls=False, exec_order=DEFAULT_ACTION_ORDER):
|
|
"""
|
|
Function decorator that registers and configures action.
|
|
|
|
:param in_action - function to register
|
|
:param global_action - make the function global, i.e. make it be
|
|
only called once.
|
|
:param log_calls - at every call to action, a useful log will be printed.
|
|
:param exec_order - action's calling order.
|
|
"""
|
|
def append_action(action):
|
|
action = _ConfiguredAction(action, exec_order, global_action, log_calls)
|
|
bisect.insort(SpSetupActions.actions, action)
|
|
return action
|
|
if in_action is not None:
|
|
return append_action(in_action)
|
|
return append_action
|
|
|
|
def run_actions(sp_layout: dict, args: dict, verbose=False):
|
|
"""
|
|
Executes all actions in accordance to their registering configuration:
|
|
- If set as "global" it will be called once.
|
|
- Actions are called respecting the order established by their "exec_order" field.
|
|
|
|
:param sp_layout - dictionary containing the SP layout information.
|
|
:param args - arguments to be propagated through the call of actions.
|
|
:param verbose - prints actions information in order of execution.
|
|
"""
|
|
args["called"] = [] # for debug purposes
|
|
def append_called(action, sp, args :dict):
|
|
args["called"].append(f"{action.__name__} -> {sp}")
|
|
return args
|
|
|
|
for action in SpSetupActions.actions:
|
|
if verbose:
|
|
print(f"Calling {action}")
|
|
if action.global_action:
|
|
scope = "global"
|
|
args = action(sp_layout, scope, args)
|
|
args = append_called(action, scope, args)
|
|
else:
|
|
# Functions that are not global called for each SP defined in
|
|
# the SP layout.
|
|
for sp in sp_layout.keys():
|
|
args = action(sp_layout, sp, args)
|
|
args = append_called(action, sp, args)
|
|
|
|
if __name__ == "__main__":
|
|
# Executing this module will have the following test code/playground executed
|
|
sp_layout = {
|
|
"partition1" : {
|
|
"boot-info": True,
|
|
"image": {
|
|
"file": "partition.bin",
|
|
"offset":"0x2000"
|
|
},
|
|
"pm": {
|
|
"file": "cactus.dts",
|
|
"offset":"0x1000"
|
|
},
|
|
"owner": "SiP"
|
|
},
|
|
"partition2" : {
|
|
"image": "partition.bin",
|
|
"pm": "cactus-secondary.dts",
|
|
"owner": "Plat"
|
|
},
|
|
"partition3" : {
|
|
"image": "partition.bin",
|
|
"pm": "cactus-tertiary.dts",
|
|
"owner": "Plat"
|
|
},
|
|
"partition4" : {
|
|
"image": "ivy.bin",
|
|
"pm": "ivy.dts",
|
|
"owner": "Plat"
|
|
}
|
|
}
|
|
|
|
#Example of how to use this module
|
|
@SpSetupActions.sp_action(global_action=True)
|
|
def my_action1(sp_layout, _, args :dict):
|
|
print(f"inside function my_action1{sp_layout}\n\n args:{args})")
|
|
return args # Always return args in action function.
|
|
@SpSetupActions.sp_action(exec_order=1)
|
|
def my_action2(sp_layout, sp_name, args :dict):
|
|
print(f"inside function my_action2; SP: {sp_name} {sp_layout} args:{args}")
|
|
return args
|
|
|
|
# Example arguments to be propagated through the functions.
|
|
# 'args' can be extended in the action functions.
|
|
args = dict()
|
|
args["arg1"] = 0xEEE
|
|
args["arg2"] = 0xFF
|
|
SpSetupActions.run_actions(sp_layout, args)
|