blob: 0962a59e1ad309d6e27817b866cc52ffc1e81760 [file] [log] [blame]
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +05301#!/usr/bin/env python3
Ioannis Glaropoulos560357b2018-11-23 09:39:53 +01002#
3# Copyright (c) 2018 Intel Corporation
4#
5# SPDX-License-Identifier: Apache-2.0
6
Andrew Boiec78c5e62019-03-11 14:45:43 -07007"""
8Script to generate a linker script organizing application memory partitions
9
10Applications may declare build-time memory domain partitions with
11K_APPMEM_PARTITION_DEFINE, and assign globals to them using K_APP_DMEM
12or K_APP_BMEM macros. For each of these partitions, we need to
13route all their data into appropriately-sized memory areas which meet the
14size/alignment constraints of the memory protection hardware.
15
16This linker script is created very early in the build process, before
17the build attempts to link the kernel binary, as the linker script this
18tool generates is a necessary pre-condition for kernel linking. We extract
19the set of memory partitions to generate by looking for variables which
20have been assigned to input sections that follow a defined naming convention.
21We also allow entire libraries to be pulled in to assign their globals
22to a particular memory partition via command line directives.
23
24This script takes as inputs:
25
26- The base directory to look for compiled objects
27- key/value pairs mapping static library files to what partitions their globals
28 should end up in.
29
30The output is a linker script fragment containing the definition of the
31app shared memory section, which is further divided, for each partition
32found, into data and BSS for each partition.
33"""
34
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053035import sys
36import argparse
37import os
38import re
Daniel Leung212ec9a2019-03-10 14:20:21 -070039from collections import OrderedDict
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053040from elftools.elf.elffile import ELFFile
Daniel Leung212ec9a2019-03-10 14:20:21 -070041from elftools.elf.sections import SymbolTableSection
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053042
Daniel Leung212ec9a2019-03-10 14:20:21 -070043SZ = 'size'
44SRC = 'sources'
45LIB = 'libraries'
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053046
Andrew Boie7adff462019-01-30 13:44:54 -080047# This script will create sections and linker variables to place the
48# application shared memory partitions.
49# these are later read by the macros defined in app_memdomain.h for
Andrew Boie4ce652e2019-02-22 16:08:44 -080050# initialization purpose when USERSPACE is enabled.
Andrew Boie686bd912019-02-01 11:52:20 -080051data_template = """
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053052 /* Auto generated code do not modify */
Andrew Boief084c382019-03-04 17:57:06 -080053 SMEM_PARTITION_ALIGN(z_data_smem_{0}_bss_end - z_data_smem_{0}_part_start);
54 z_data_smem_{0}_part_start = .;
Eugeniy Paltsev0a7b65e2020-09-02 16:52:09 +030055 KEEP(*(data_smem_{0}_data*))
Andrew Boie686bd912019-02-01 11:52:20 -080056"""
57
58library_data_template = """
Jim Shu46eb3e52021-09-28 10:03:21 +080059 *{0}:*(.data .data.* .sdata .sdata.*)
Andrew Boie686bd912019-02-01 11:52:20 -080060"""
61
62bss_template = """
Andrew Boief084c382019-03-04 17:57:06 -080063 z_data_smem_{0}_bss_start = .;
Eugeniy Paltsev0a7b65e2020-09-02 16:52:09 +030064 KEEP(*(data_smem_{0}_bss*))
Andrew Boie686bd912019-02-01 11:52:20 -080065"""
66
67library_bss_template = """
Jim Shu46eb3e52021-09-28 10:03:21 +080068 *{0}:*(.bss .bss.* .sbss .sbss.* COMMON COMMON.*)
Andrew Boie686bd912019-02-01 11:52:20 -080069"""
70
71footer_template = """
Andrew Boief084c382019-03-04 17:57:06 -080072 z_data_smem_{0}_bss_end = .;
73 SMEM_PARTITION_ALIGN(z_data_smem_{0}_bss_end - z_data_smem_{0}_part_start);
74 z_data_smem_{0}_part_end = .;
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053075"""
Andrew Boie686bd912019-02-01 11:52:20 -080076
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053077linker_start_seq = """
Daniel Leung2117a2a2021-07-12 13:33:32 -070078 SECTION_PROLOGUE(_APP_SMEM{1}_SECTION_NAME,,)
79 {{
Adithya Baglody10c6a0c2018-09-21 10:17:58 +053080 APP_SHARED_ALIGN;
Daniel Leung2117a2a2021-07-12 13:33:32 -070081 _app_smem{0}_start = .;
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053082"""
83
84linker_end_seq = """
Adithya Baglody10c6a0c2018-09-21 10:17:58 +053085 APP_SHARED_ALIGN;
Daniel Leung2117a2a2021-07-12 13:33:32 -070086 _app_smem{0}_end = .;
87 }} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
88"""
89
90empty_app_smem = """
91 SECTION_PROLOGUE(_APP_SMEM{1}_SECTION_NAME,,)
92 {{
Jaxson Hanf079e662021-08-31 14:14:03 +080093#ifdef EMPTY_APP_SHARED_ALIGN
94 EMPTY_APP_SHARED_ALIGN;
95#endif
Daniel Leung2117a2a2021-07-12 13:33:32 -070096 _app_smem{0}_start = .;
97 _app_smem{0}_end = .;
98 }} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053099"""
100
101size_cal_string = """
Andrew Boief084c382019-03-04 17:57:06 -0800102 z_data_smem_{0}_part_size = z_data_smem_{0}_part_end - z_data_smem_{0}_part_start;
103 z_data_smem_{0}_bss_size = z_data_smem_{0}_bss_end - z_data_smem_{0}_bss_start;
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530104"""
105
Eugeniy Paltsev0a7b65e2020-09-02 16:52:09 +0300106section_regex = re.compile(r'data_smem_([A-Za-z0-9_]*)_(data|bss)*')
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530107
Daniel Leung212ec9a2019-03-10 14:20:21 -0700108elf_part_size_regex = re.compile(r'z_data_smem_(.*)_part_size')
109
110def find_obj_file_partitions(filename, partitions):
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530111 with open(filename, 'rb') as f:
Ulf Magnusson0d39a102019-09-06 11:13:19 +0200112 full_lib = ELFFile(f)
Ulf Magnussonba312fe2019-03-20 19:30:29 +0100113 if not full_lib:
Ulf Magnussone9c1d6d2019-03-20 22:40:22 +0100114 sys.exit("Error parsing file: " + filename)
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530115
Andrew Boie7adff462019-01-30 13:44:54 -0800116 sections = [x for x in full_lib.iter_sections()]
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530117 for section in sections:
Andrew Boie7adff462019-01-30 13:44:54 -0800118 m = section_regex.match(section.name)
119 if not m:
120 continue
Andrew Boie686bd912019-02-01 11:52:20 -0800121
Andrew Boie7adff462019-01-30 13:44:54 -0800122 partition_name = m.groups()[0]
Andrew Boie686bd912019-02-01 11:52:20 -0800123 if partition_name not in partitions:
Daniel Leung212ec9a2019-03-10 14:20:21 -0700124 partitions[partition_name] = {SZ: section.header.sh_size}
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530125
Daniel Leung212ec9a2019-03-10 14:20:21 -0700126 if args.verbose:
127 partitions[partition_name][SRC] = filename
128
129 else:
130 partitions[partition_name][SZ] += section.header.sh_size
131
132
133 return partitions
134
135
136def parse_obj_files(partitions):
137 # Iterate over all object files to find partitions
Ulf Magnusson12ba9df2019-03-19 19:28:24 +0100138 for dirpath, _, files in os.walk(args.directory):
Daniel Leung212ec9a2019-03-10 14:20:21 -0700139 for filename in files:
Ulf Magnusson0d39a102019-09-06 11:13:19 +0200140 if re.match(r".*\.obj$", filename):
Daniel Leung212ec9a2019-03-10 14:20:21 -0700141 fullname = os.path.join(dirpath, filename)
142 find_obj_file_partitions(fullname, partitions)
143
144
145def parse_elf_file(partitions):
146 with open(args.elf, 'rb') as f:
147 elffile = ELFFile(f)
148
149 symbol_tbls = [s for s in elffile.iter_sections()
150 if isinstance(s, SymbolTableSection)]
151
152 for section in symbol_tbls:
Ulf Magnusson12ba9df2019-03-19 19:28:24 +0100153 for symbol in section.iter_symbols():
Daniel Leung212ec9a2019-03-10 14:20:21 -0700154 if symbol['st_shndx'] != "SHN_ABS":
155 continue
156
157 x = elf_part_size_regex.match(symbol.name)
158 if not x:
159 continue
160
161 partition_name = x.groups()[0]
162 size = symbol['st_value']
163 if partition_name not in partitions:
164 partitions[partition_name] = {SZ: size}
165
166 if args.verbose:
167 partitions[partition_name][SRC] = args.elf
168
169 else:
170 partitions[partition_name][SZ] += size
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530171
Andrew Boie686bd912019-02-01 11:52:20 -0800172
Daniel Leung2117a2a2021-07-12 13:33:32 -0700173def generate_final_linker(linker_file, partitions, lnkr_sect=""):
174 string = ""
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530175
Daniel Leung2117a2a2021-07-12 13:33:32 -0700176 if len(partitions) > 0:
177 string = linker_start_seq.format(lnkr_sect, lnkr_sect.upper())
178 size_string = ''
179 for partition, item in partitions.items():
180 string += data_template.format(partition)
181 if LIB in item:
182 for lib in item[LIB]:
183 string += library_data_template.format(lib)
184 string += bss_template.format(partition, lnkr_sect)
185 if LIB in item:
186 for lib in item[LIB]:
187 string += library_bss_template.format(lib)
188 string += footer_template.format(partition)
189 size_string += size_cal_string.format(partition)
190
191 string += linker_end_seq.format(lnkr_sect)
192 string += size_string
193 else:
194 string = empty_app_smem.format(lnkr_sect, lnkr_sect.upper())
195
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530196 with open(linker_file, "w") as fw:
197 fw.write(string)
198
199
200def parse_args():
201 global args
202 parser = argparse.ArgumentParser(
203 description=__doc__,
204 formatter_class=argparse.RawDescriptionHelpFormatter)
Daniel Leung212ec9a2019-03-10 14:20:21 -0700205 parser.add_argument("-d", "--directory", required=False, default=None,
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530206 help="Root build directory")
Daniel Leung212ec9a2019-03-10 14:20:21 -0700207 parser.add_argument("-e", "--elf", required=False, default=None,
208 help="ELF file")
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530209 parser.add_argument("-o", "--output", required=False,
210 help="Output ld file")
Ulf Magnusson0d39a102019-09-06 11:13:19 +0200211 parser.add_argument("-v", "--verbose", action="count", default=0,
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530212 help="Verbose Output")
Andrew Boie686bd912019-02-01 11:52:20 -0800213 parser.add_argument("-l", "--library", nargs=2, action="append", default=[],
214 metavar=("LIBRARY", "PARTITION"),
215 help="Include globals for a particular library or object filename into a designated partition")
Daniel Leung2117a2a2021-07-12 13:33:32 -0700216 parser.add_argument("--pinoutput", required=False,
217 help="Output ld file for pinned sections")
218 parser.add_argument("--pinpartitions", action="store", required=False, default="",
219 help="Comma separated names of partitions to be pinned in physical memory")
Andrew Boie686bd912019-02-01 11:52:20 -0800220
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530221 args = parser.parse_args()
222
223
224def main():
225 parse_args()
Andrew Boie686bd912019-02-01 11:52:20 -0800226 partitions = {}
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530227
Daniel Leung212ec9a2019-03-10 14:20:21 -0700228 if args.directory is not None:
229 parse_obj_files(partitions)
230 elif args.elf is not None:
231 parse_elf_file(partitions)
232 else:
233 return
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530234
Andrew Boie686bd912019-02-01 11:52:20 -0800235 for lib, ptn in args.library:
236 if ptn not in partitions:
Daniel Leung212ec9a2019-03-10 14:20:21 -0700237 partitions[ptn] = {}
Andrew Boie686bd912019-02-01 11:52:20 -0800238
Daniel Leung212ec9a2019-03-10 14:20:21 -0700239 if LIB not in partitions[ptn]:
240 partitions[ptn][LIB] = [lib]
241 else:
242 partitions[ptn][LIB].append(lib)
243
Daniel Leung2117a2a2021-07-12 13:33:32 -0700244 if args.pinoutput:
245 pin_part_names = args.pinpartitions.split(',')
246
247 generic_partitions = {key: value for key, value in partitions.items()
248 if key not in pin_part_names}
249 pinned_partitions = {key: value for key, value in partitions.items()
250 if key in pin_part_names}
251 else:
252 generic_partitions = partitions
Marc Herberteefea9d2019-06-27 16:09:26 -0700253
254 # Sample partitions.items() list before sorting:
255 # [ ('part1', {'size': 64}), ('part3', {'size': 64}, ...
256 # ('part0', {'size': 334}) ]
Daniel Leung2117a2a2021-07-12 13:33:32 -0700257 decreasing_tuples = sorted(generic_partitions.items(),
Marc Herberteefea9d2019-06-27 16:09:26 -0700258 key=lambda x: (x[1][SZ], x[0]), reverse=True)
259
260 partsorted = OrderedDict(decreasing_tuples)
Daniel Leung212ec9a2019-03-10 14:20:21 -0700261
262 generate_final_linker(args.output, partsorted)
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530263 if args.verbose:
Andrew Boie7adff462019-01-30 13:44:54 -0800264 print("Partitions retrieved:")
Daniel Leung212ec9a2019-03-10 14:20:21 -0700265 for key in partsorted:
266 print(" {0}: size {1}: {2}".format(key,
267 partsorted[key][SZ],
268 partsorted[key][SRC]))
269
Daniel Leung2117a2a2021-07-12 13:33:32 -0700270 if args.pinoutput:
271 decreasing_tuples = sorted(pinned_partitions.items(),
272 key=lambda x: (x[1][SZ], x[0]), reverse=True)
273
274 partsorted = OrderedDict(decreasing_tuples)
275
276 generate_final_linker(args.pinoutput, partsorted, lnkr_sect="_pinned")
277 if args.verbose:
278 print("Pinned partitions retrieved:")
279 for key in partsorted:
280 print(" {0}: size {1}: {2}".format(key,
281 partsorted[key][SZ],
282 partsorted[key][SRC]))
283
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530284
285if __name__ == '__main__':
286 main()