Skip to content

Commit 3cadb54

Browse files
jaccoo01adeaarm
authored andcommitted
RSE: Add routing table header and generate
Add a new header which defines two structures for the RSE routing tables. One of these is the local routing tables for a single RSE and the second structure is for the whole system. Note that the single RSE routing tables can in theory contain tables for more than just the other RSEs in the system and in future the NUM_NODES will be extended to support this. We also add a new routing_tables.py module in a similar vein to the other provisioning modules. This contains a class definition and logic to parse the existing layout (TGF files). This script is then added to the build system and called to generate a pickle file which will be consumed by other CMake logic to add these routing tables to the RSE build. Change-Id: Ie5998a62d48c3cb1f7f8d7dad9a24bf4150b67e5 Signed-off-by: Jackson Cooper-Driver <[email protected]>
1 parent 905090c commit 3cadb54

File tree

4 files changed

+226
-1
lines changed

4 files changed

+226
-1
lines changed

platform/ext/target/arm/rse/common/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,27 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/config/otp_layout.csv
896896
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/config/otp_layout.csv
897897
DESTINATION ${INSTALL_PLATFORM_NS_DIR}/config)
898898
899+
############################## Routing tables ##################################
900+
901+
if (RSE_AMOUNT GREATER 1)
902+
add_custom_target(routing_tables_pickle
903+
ALL
904+
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/config/routing_tables.pickle
905+
)
906+
907+
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/config/routing_tables.pickle
908+
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/rse_routing_tables.h
909+
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/scripts/modules/routing_tables.py
910+
DEPENDS ${MULTI_RSE_TOPOLOGY_FILE}
911+
COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${CMAKE_SOURCE_DIR}/tools/modules
912+
${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/modules/routing_tables.py
913+
--rse_routing_tables_h_file=${CMAKE_CURRENT_SOURCE_DIR}/rse_routing_tables.h
914+
--compile_commands_file=${CMAKE_BINARY_DIR}/compile_commands.json
915+
--topology_graph_file=${MULTI_RSE_TOPOLOGY_FILE}
916+
--routing_tables_output_file=${CMAKE_CURRENT_BINARY_DIR}/config/routing_tables.pickle
917+
)
918+
endif()
919+
899920
#========================= Files for building NS side platform ================#
900921
901922
install(FILES device/source/device_definition.c

platform/ext/target/arm/rse/common/rse_handshake/rse_handshake.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023-2024 Arm Limited. All rights reserved.
2+
* SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
33
*
44
* Licensed under the Apache License Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
2626
#include "cc3xx_rng.h"
2727
#include "cmsis.h"
2828
#include "dpa_hardened_word_copy.h"
29+
#include "rse_routing_tables.h"
2930

3031
#include <string.h>
3132

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*
6+
*/
7+
8+
#ifndef __RSE_ROUTING_TABLES_H__
9+
#define __RSE_ROUTING_TABLES_H__
10+
11+
#include <stdint.h>
12+
13+
#ifdef __cplusplus
14+
extern "C" {
15+
#endif
16+
17+
#define RSE_ROUTING_TABLES_ALIGN(x, bound) ((((x) + bound - 1) / bound) * bound)
18+
19+
/* Initially only RSE<->RSE comms but this can
20+
* be extended to support comms with other components */
21+
#define NUM_NODES (RSE_AMOUNT)
22+
23+
struct rse_single_node_routing_tables_t {
24+
/* These fields can be placed in the OTP and therefore
25+
* must be word aligned */
26+
uint8_t send[RSE_ROUTING_TABLES_ALIGN(NUM_NODES, sizeof(uint32_t))];
27+
uint8_t receive[RSE_ROUTING_TABLES_ALIGN(NUM_NODES, sizeof(uint32_t))];
28+
};
29+
30+
struct rse_whole_system_routing_tables_t {
31+
struct rse_single_node_routing_tables_t routing_table[RSE_AMOUNT];
32+
};
33+
34+
#ifdef __cplusplus
35+
}
36+
#endif
37+
38+
#endif /* __RSE_ROUTING_TABLES_H__ */
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#!/usr/bin/env python3
2+
#-------------------------------------------------------------------------------
3+
# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
4+
#
5+
# SPDX-License-Identifier: BSD-3-Clause
6+
#
7+
#-------------------------------------------------------------------------------
8+
9+
import arg_utils
10+
import c_struct
11+
import c_macro
12+
import c_include
13+
import argparse
14+
import pickle
15+
import re
16+
import networkx as nx
17+
18+
import logging
19+
logger = logging.getLogger("TF-M.{}".format(__name__))
20+
21+
def add_arguments(parser : argparse.ArgumentParser,
22+
prefix : str = "",
23+
required : bool = True,
24+
) -> None:
25+
26+
return arg_utils.add_prefixed_argument(parser, "routing_tables", prefix=prefix,
27+
help="Path to routing tables pickle",
28+
type=Routing_tables.from_config_file,
29+
required=required)
30+
31+
def parse_args(args : argparse.Namespace,
32+
prefix : str = "",
33+
) -> dict:
34+
out = {}
35+
36+
if "routing_tables" not in out.keys():
37+
out |= arg_utils.parse_args_automatically(args, ["routing_tables"], prefix)
38+
39+
return out
40+
41+
42+
def load_graph(filename):
43+
assert(filename[-4:] == ".tgf")
44+
45+
with open(filename, 'rt') as graph_file:
46+
lines = graph_file.readlines()
47+
48+
graph = nx.DiGraph()
49+
50+
re_line = re.compile(r"(\d+) (\d+) Send (\d+) Receive (\d+)")
51+
re_node = re.compile(r"(\d+) ([a-zA-Z0-9]+)")
52+
edge = [0] * 2
53+
54+
for line in lines:
55+
line_match = re_line.match(line)
56+
node_match = re_node.match(line)
57+
if line_match is not None:
58+
edge[0], edge[1], send, recieve = line_match.groups()
59+
graph.add_edge(int(edge[0]), int(edge[1]), send=int(send), recieve=int(recieve))
60+
elif node_match is not None:
61+
graph.add_node(int(node_match.groups()[0]))
62+
else:
63+
assert line.strip() == ''
64+
65+
return graph
66+
67+
def routing_tables_from_graph(graph, rse_id, num_nodes):
68+
send_table = [0] * num_nodes
69+
recieve_table = [0] * num_nodes
70+
71+
for destination in range(num_nodes):
72+
if destination is rse_id:
73+
continue
74+
75+
logger.info("Finding path from {} to {}".format(rse_id, destination))
76+
path = nx.shortest_path(graph, rse_id, destination)
77+
nexthop = path[1]
78+
send_table[destination] = graph[rse_id][nexthop]['send']
79+
recieve_table[destination] = graph[rse_id][nexthop]['recieve']
80+
81+
send_table_bytes = bytes(0)
82+
for table_entry in send_table:
83+
send_table_bytes += table_entry.to_bytes(1, byteorder='little')
84+
85+
recieve_table_bytes = bytes(0)
86+
for table_entry in recieve_table:
87+
recieve_table_bytes += table_entry.to_bytes(1, byteorder='little')
88+
89+
return send_table_bytes, recieve_table_bytes
90+
91+
class Routing_tables:
92+
def __init__(self, routing_tables):
93+
self.routing_tables = routing_tables
94+
95+
@staticmethod
96+
def from_h_file(h_file_path, includes, defines):
97+
routing_tables_struct = c_struct.C_struct.from_h_file(h_file_path,
98+
"rse_whole_system_routing_tables_t",
99+
includes, defines)
100+
101+
return Routing_tables(routing_tables_struct)
102+
103+
@staticmethod
104+
def from_config_file(file_path):
105+
with open(file_path, "rb") as f:
106+
return pickle.load(f)
107+
108+
def get_number_rses(self):
109+
return self.routing_tables.routing_table.get_size() // self.routing_tables.routing_table[0].get_size()
110+
111+
def get_routing_tables_source(self):
112+
return self.routing_tables.get_value_str()
113+
114+
def get_routing_tables_bytes(self):
115+
return self.routing_tables.to_bytes()
116+
117+
def set_routing_tables_bytes(self, value):
118+
self.routing_tables.set_value_from_bytes(value)
119+
120+
def get_rse_routing_table_bytes(self, rse_id):
121+
return self.routing_tables.routing_table[rse_id].to_bytes()
122+
123+
def set_rse_routing_table_bytes(self, rse_id, send, receive):
124+
self.routing_tables.routing_table[rse_id].send.set_value_from_bytes(send)
125+
self.routing_tables.routing_table[rse_id].receive.set_value_from_bytes(receive)
126+
127+
def to_config_file(self, file_path):
128+
with open(file_path, "wb") as f:
129+
pickle.dump(self, f)
130+
131+
script_description = """
132+
This script takes an input of the header file containing the RSE routing tables
133+
definition and uses the TGF file definition to populate this structure with the
134+
defined routing tables. This structure is then output to a pickle file where it
135+
can be used by other scripts (such as the OTP config generation script)
136+
"""
137+
138+
if __name__ == "__main__":
139+
parser = argparse.ArgumentParser(allow_abbrev=False,
140+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
141+
description=script_description)
142+
parser.add_argument("--rse_routing_tables_h_file", help="path to rse_routing_tables.h", type=arg_utils.arg_type_filepath, required=True)
143+
parser.add_argument("--compile_commands_file", help="path to compile_commands.json", type=arg_utils.arg_type_filepath, required=True)
144+
parser.add_argument("--topology_graph_file", help="The topology graph file expressing the system", type=arg_utils.arg_type_filepath, required=True)
145+
parser.add_argument("--routing_tables_output_file", help="file to output routing tables to", required=True)
146+
parser.add_argument("--log_level", help="log level", required=False, default="ERROR", choices=logging._levelToName.values())#
147+
148+
args = parser.parse_args()
149+
logging.getLogger("TF-M").setLevel(args.log_level)
150+
logger.addHandler(logging.StreamHandler())
151+
152+
includes = c_include.get_includes(args.compile_commands_file, "rse_handshake.c")
153+
defines = c_include.get_defines(args.compile_commands_file, "rse_handshake.c")
154+
155+
routing_tables = Routing_tables.from_h_file(args.rse_routing_tables_h_file, includes, defines)
156+
157+
graph = load_graph(args.topology_graph_file)
158+
number_rses = routing_tables.get_number_rses()
159+
number_nodes = graph.number_of_nodes()
160+
# Assumes that RSE nodes are defined before any other components
161+
for rse_id in range(number_rses):
162+
send_table_bytes, receive_table_bytes = routing_tables_from_graph(graph, rse_id, number_nodes)
163+
routing_tables.set_rse_routing_table_bytes(rse_id, send_table_bytes, receive_table_bytes)
164+
165+
routing_tables.to_config_file(args.routing_tables_output_file)

0 commit comments

Comments
 (0)