Skip to content

Commit 753efbb

Browse files
committed
[rp2040] elf2uf2 review
1 parent 4190846 commit 753efbb

File tree

2 files changed

+54
-44
lines changed

2 files changed

+54
-44
lines changed

tools/build_script_generator/scons/site_tools/elf2uf2.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,17 @@
1717
from modm_tools import elf2uf2
1818

1919
def elf2uf2_action(target, source, env):
20+
memranges = []
21+
for conf in env['CONFIG_DEVICE_MEMORY']:
22+
memranges.append({
23+
"start": conf['start'],
24+
"end": conf['start'] + conf['size'],
25+
"type": conf['name'] == 'flash' and 'CONTENTS' or 'NO_CONTENTS'
26+
})
2027
elf2uf2.convert(str(source[0]),
21-
str(target[0]),env['CONFIG_DEVICE_NAME'])
28+
str(target[0]),
29+
env['CONFIG_DEVICE_NAME'],
30+
memranges)
2231

2332
def generate(env, **kw):
2433

tools/modm_tools/elf2uf2.py

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,28 @@
1010
# Authors:
1111
# - 2022, Andrey Kunitsyn
1212

13+
"""
14+
### elf2uf2 - Elf to UF2 Converter
15+
16+
UF2 file format info : https://github.com/microsoft/uf2
17+
18+
```sh
19+
python3 modm/modm_tools/elf2uf2.py firmware.elf -o firmware.uf2 --target rp2040 \
20+
--range 0x10000000:0x15000000:CONTENTS \
21+
--range 0x20000000:0x20042000:NO_CONTENTS
22+
23+
# converts `firmware.elf` to `firmware.uf2` in the CWD
24+
```
25+
"""
26+
1327
import os
1428
import struct
1529

1630
from pathlib import Path
1731

1832
verbose = False
1933

20-
# we require 256 (as this is the page size supported by the device)
21-
LOG2_PAGE_SIZE = 8 # @todo configurable
22-
PAGE_SIZE = (1 << LOG2_PAGE_SIZE)
2334

24-
# @todo read from modm-device
25-
memory_map = {
26-
"rp2040": {
27-
"flash": [
28-
{"start":0x10000000,"end":0x15000000,"type":"CONTENTS"},
29-
{"start":0x20000000,"end":0x20042000,"type":"NO_CONTENTS"},
30-
{"start":0x21000000,"end":0x21040000,"type":"NO_CONTENTS"},
31-
],
32-
"ram": [
33-
{"start":0x20000000,"end":0x20042000,"type":"CONTENTS"},
34-
{"start":0x15000000,"end":0x15004000,"type":"CONTENTS"},
35-
{"start":0x00000000,"end":0x00004000,"type":"IGNORE"}, #// for now we ignore the bootrom if present
36-
]
37-
}
38-
}
3935

4036
UF2_FLAG_NOT_MAIN_FLASH = 0x00000001
4137
UF2_FLAG_FILE_CONTAINER = 0x00001000
@@ -49,6 +45,7 @@
4945
"MAGIC_START1": 0x9E5D5157,
5046
"MAGIC_END": 0x0AB16F30,
5147
"FAMILY_ID": 0xe48bff56,
48+
"PAGE_SIZE": (1 << 8),
5249
}
5350
}
5451

@@ -151,7 +148,7 @@ def check_address_range(valid_ranges, addr, vaddr, size, uninitialized):
151148
return range
152149
raise Exception("Memory segment {:08x}->{:08x} is outside of valid address range for device".format(addr, addr+size))
153150

154-
def read_and_check_elf32_ph_entries(buffer, eh, valid_ranges, pages):
151+
def read_and_check_elf32_ph_entries(buffer, eh, valid_ranges, pages, page_size):
155152
for i in range(eh[6]):
156153
entry = struct.unpack_from(elf32_ph_entry,buffer,eh[1]+i*elf32_ph_entry_size)
157154
if entry[0] == PT_LOAD and entry[5] !=0:
@@ -167,8 +164,8 @@ def read_and_check_elf32_ph_entries(buffer, eh, valid_ranges, pages):
167164
remaining = mapped_size;
168165
file_offset = entry[1];
169166
while remaining > 0:
170-
off = addr & (PAGE_SIZE - 1)
171-
chlen = min(remaining, PAGE_SIZE - off)
167+
off = addr & (page_size - 1)
168+
chlen = min(remaining, page_size - off)
172169
key = addr - off
173170
fragments = []
174171
if key in pages:
@@ -201,32 +198,17 @@ def realize_page(buffer, fragments):
201198
raise Exception("failed concat")
202199
return result
203200

204-
def is_address_initialized(valid_ranges, addr):
205-
for range in valid_ranges:
206-
if range["start"] <= addr and range["end"] > addr:
207-
return range["type"] == "CONTENTS"
208-
return False
209201

210-
def convert_data(source_bytes,target):
202+
def convert_data(source_bytes,target,ranges):
211203
eh = read_header(source_bytes)
212-
ranges = None
213-
ranges_name = None
214-
memory_variants = memory_map[target]
215-
for name,memranges in memory_variants.items():
216-
if is_address_initialized(memranges,eh[0]):
217-
ranges = memranges
218-
ranges_name = name
219-
break
220-
if not ranges:
221-
raise Exception("Not found memory range")
204+
config = uf2_config[target]
222205
if verbose:
223-
print('Build for chip:{} mem:{}'.format(target,ranges_name))
206+
print('Build for chip:{}'.format(target))
224207
pages = {}
225-
read_and_check_elf32_ph_entries(source_bytes,eh,ranges,pages)
208+
read_and_check_elf32_ph_entries(source_bytes,eh,ranges,pages,config["PAGE_SIZE"])
226209
if len(pages) == 0:
227210
raise Exception("The input file has no memory pages")
228211

229-
config = uf2_config[target]
230212
num_blocks = len(pages)
231213
page_num = 0
232214
file_content = bytes(0)
@@ -240,7 +222,7 @@ def convert_data(source_bytes,target):
240222
config["MAGIC_START1"],
241223
UF2_FLAG_FAMILY_ID_PRESENT,
242224
target_addr,
243-
PAGE_SIZE,
225+
config["PAGE_SIZE"],
244226
page_num,
245227
num_blocks,
246228
config["FAMILY_ID"]) + data + struct.pack('<I',config["MAGIC_END"])
@@ -250,11 +232,16 @@ def convert_data(source_bytes,target):
250232
file_content += block
251233
return file_content
252234

253-
def convert(source, output, target):
235+
def convert(source, output, target, ranges):
254236
source_bytes = Path(source).read_bytes()
255-
uf2 = convert_data(source_bytes,target)
237+
uf2 = convert_data(source_bytes,target, ranges)
256238
Path(output).write_bytes(uf2)
257239

240+
def parse_range(strval):
241+
if strval.startswith('0x'):
242+
return int(strval[2:],16)
243+
return int(strval)
244+
258245
if __name__ == "__main__":
259246
import argparse
260247

@@ -266,6 +253,7 @@ def convert(source, output, target):
266253
parser.add_argument(
267254
"-o", "--output",
268255
dest="output",
256+
required=True,
269257
help="Destination UF2 image")
270258
parser.add_argument(
271259
"--verbose",
@@ -277,8 +265,21 @@ def convert(source, output, target):
277265
dest="target",
278266
default="rp2040",
279267
help="Target chip")
268+
parser.add_argument(
269+
"--range",
270+
nargs='+',
271+
dest="ranges",
272+
help="Memory range in format start:end:type, where type NO_CONTENTS|CONTENTS|IGNORE")
280273

281274
args = parser.parse_args()
282275
verbose = args.verbose
276+
ranges = []
277+
for r in args.ranges:
278+
start,end,t = r.split(':')
279+
ranges.append({
280+
"start": parse_range(start),
281+
"end": parse_range(end),
282+
"type": t
283+
})
283284

284285
convert(args.source,args.output,args.target)

0 commit comments

Comments
 (0)