Skip to content

Commit 7e5cb9e

Browse files
committed
Add generate_flash_algo.py script.
Copied the script from the generate_blobs.py script in the FlashAlgo project, but simplified and reused code from pyocd.
1 parent ed41c19 commit 7e5cb9e

File tree

1 file changed

+201
-0
lines changed

1 file changed

+201
-0
lines changed

scripts/generate_flash_algo.py

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
#!/usr/bin/env python3
2+
# pyOCD debugger
3+
# Copyright (c) 2011-2020 Arm Limited
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
18+
from __future__ import print_function
19+
import os
20+
import argparse
21+
import struct
22+
import binascii
23+
import logging
24+
import jinja2
25+
from pyocd.target.pack.flash_algo import PackFlashAlgo
26+
27+
# TODO
28+
# FIXED LENGTH - remove and these (shrink offset to 4 for bkpt only)
29+
BLOB_HEADER = '0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2,'
30+
HEADER_SIZE = 0x20
31+
32+
STACK_SIZE = 0x200
33+
34+
PYOCD_TEMPLATE = \
35+
"""# pyOCD debugger
36+
# Copyright (c) 2017-2020 Arm Limited
37+
# SPDX-License-Identifier: Apache-2.0
38+
#
39+
# Licensed under the Apache License, Version 2.0 (the "License");
40+
# you may not use this file except in compliance with the License.
41+
# You may obtain a copy of the License at
42+
#
43+
# http://www.apache.org/licenses/LICENSE-2.0
44+
#
45+
# Unless required by applicable law or agreed to in writing, software
46+
# distributed under the License is distributed on an "AS IS" BASIS,
47+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
48+
# See the License for the specific language governing permissions and
49+
# limitations under the License.
50+
51+
FLASH_ALGO_{{name|upper}} = {
52+
'load_address' : {{'0x%08x' % entry}},
53+
54+
# Flash algorithm as a hex string
55+
'instructions': [
56+
{{prog_header}}
57+
{{algo.format_algo_data(4, 8, "c")}}
58+
],
59+
60+
# Relative function addresses
61+
'pc_init': {{'0x%08x' % (algo.symbols['Init'] + header_size + entry)}},
62+
'pc_unInit': {{'0x%08x' % (algo.symbols['UnInit'] + header_size + entry)}},
63+
'pc_program_page': {{'0x%08x' % (algo.symbols['ProgramPage'] + header_size + entry)}},
64+
'pc_erase_sector': {{'0x%08x' % (algo.symbols['EraseSector'] + header_size + entry)}},
65+
'pc_eraseAll': {{'0x%08x' % (algo.symbols['EraseChip'] + header_size + entry)}},
66+
67+
'static_base' : {{'0x%08x' % entry}} + {{'0x%08x' % header_size}} + {{'0x%08x' % algo.rw_start}},
68+
'begin_stack' : {{'0x%08x' % stack_pointer}},
69+
'begin_data' : {{'0x%08x' % entry}} + 0x1000,
70+
'page_size' : {{'0x%x' % algo.page_size}},
71+
'analyzer_supported' : False,
72+
'analyzer_address' : 0x00000000,
73+
'page_buffers' : [{{'0x%08x' % (entry + 4096)}}, {{'0x%08x' % (entry + 4096 + algo.page_size)}}], # Enable double buffering
74+
'min_program_length' : {{'0x%x' % algo.page_size}},
75+
76+
# Relative region addresses and sizes
77+
'ro_start': {{'0x%x' % algo.ro_start}},
78+
'ro_size': {{'0x%x' % algo.ro_size}},
79+
'rw_start': {{'0x%x' % algo.rw_start}},
80+
'rw_size': {{'0x%x' % algo.rw_size}},
81+
'zi_start': {{'0x%x' % algo.zi_start}},
82+
'zi_size': {{'0x%x' % algo.zi_size}},
83+
84+
# Flash information
85+
'flash_start': {{'0x%x' % algo.flash_start}},
86+
'flash_size': {{'0x%x' % algo.flash_size}},
87+
'sector_sizes': (
88+
{%- for start, size in algo.sector_sizes %}
89+
{{ "(0x%x, 0x%x)" % (start, size) }},
90+
{%- endfor %}
91+
)
92+
}
93+
"""
94+
95+
def str_to_num(val):
96+
return int(val,0) #convert string to number and automatically handle hex conversion
97+
98+
class PackFlashAlgoGenerator(PackFlashAlgo):
99+
"""
100+
Class to wrap a flash algo
101+
102+
This class is intended to provide easy access to the information
103+
provided by a flash algorithm, such as symbols and the flash
104+
algorithm itself.
105+
"""
106+
107+
def format_algo_data(self, spaces, group_size, fmt):
108+
""""
109+
Return a string representing algo_data suitable for use in a template
110+
111+
The string is intended for use in a template.
112+
113+
:param spaces: The number of leading spaces for each line
114+
:param group_size: number of elements per line (element type
115+
depends of format)
116+
:param fmt: - format to create - can be either "hex" or "c"
117+
"""
118+
padding = " " * spaces
119+
if fmt == "hex":
120+
blob = binascii.b2a_hex(self.algo_data)
121+
line_list = []
122+
for i in xrange(0, len(blob), group_size):
123+
line_list.append('"' + blob[i:i + group_size] + '"')
124+
return ("\n" + padding).join(line_list)
125+
elif fmt == "c":
126+
blob = self.algo_data[:]
127+
pad_size = 0 if len(blob) % 4 == 0 else 4 - len(blob) % 4
128+
blob = blob + b"\x00" * pad_size
129+
integer_list = struct.unpack("<" + "L" * (len(blob) // 4), blob)
130+
line_list = []
131+
for pos in range(0, len(integer_list), group_size):
132+
group = ["0x%08x" % value for value in
133+
integer_list[pos:pos + group_size]]
134+
line_list.append(", ".join(group))
135+
return (",\n" + padding).join(line_list)
136+
else:
137+
raise Exception("Unsupported format %s" % fmt)
138+
139+
def process_template(self, template_text, output_path, data_dict=None):
140+
"""
141+
Generate output from the supplied template
142+
143+
All the public methods and fields of this class can be accessed from
144+
the template via "algo".
145+
146+
:param template_path: Relative or absolute file path to the template
147+
:param output_path: Relative or absolute file path to create
148+
:param data_dict: Additional data to use when generating
149+
"""
150+
if data_dict is None:
151+
data_dict = {}
152+
else:
153+
assert isinstance(data_dict, dict)
154+
data_dict = dict(data_dict)
155+
assert "algo" not in data_dict, "algo already set by user data"
156+
data_dict["algo"] = self
157+
158+
template = jinja2.Template(template_text)
159+
target_text = template.render(data_dict)
160+
161+
with open(output_path, "w") as file_handle:
162+
file_handle.write(target_text)
163+
164+
def main():
165+
parser = argparse.ArgumentParser(description="Blob generator")
166+
parser.add_argument("elf_path", help="Elf, axf, or flm to extract "
167+
"flash algo from")
168+
parser.add_argument("--blob_start", default=0x20000000, type=str_to_num, help="Starting "
169+
"address of the flash blob. Used only for DAPLink.")
170+
args = parser.parse_args()
171+
172+
with open(args.elf_path, "rb") as file_handle:
173+
algo = PackFlashAlgoGenerator(file_handle)
174+
175+
print(algo.flash_info)
176+
177+
template_dir = os.path.dirname(os.path.realpath(__file__))
178+
output_dir = os.path.dirname(args.elf_path)
179+
180+
# Allocate stack after algo and its rw data, rounded up.
181+
SP = args.blob_start + HEADER_SIZE + algo.rw_start + algo.rw_size + STACK_SIZE
182+
SP = (SP + 0x100 - 1) // 0x100 * 0x100
183+
184+
data_dict = {
185+
'name': os.path.splitext(os.path.split(args.elf_path)[-1])[0],
186+
'prog_header': BLOB_HEADER,
187+
'header_size': HEADER_SIZE,
188+
'entry': args.blob_start,
189+
'stack_pointer': SP,
190+
}
191+
192+
tmpl_name_list = [
193+
(PYOCD_TEMPLATE, "pyocd_blob.py"),
194+
]
195+
196+
for tmpl, name in tmpl_name_list:
197+
algo.process_template(tmpl, name, data_dict)
198+
199+
200+
if __name__ == '__main__':
201+
main()

0 commit comments

Comments
 (0)