mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
89 lines
3.6 KiB
Python
Executable File
89 lines
3.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
"""Verify that a pair of .bin/.elf has the particle_monofirmware_module_info at
|
|
the right place. If there is a particle_monofirmware_checksum symbol, verify
|
|
that the module_info says the firmware ends at it, and populate the
|
|
checksum. Otherwise, append the checksum and set the end-of-firmware field
|
|
accordingly."""
|
|
|
|
import os
|
|
import sys
|
|
import zlib
|
|
import subprocess
|
|
import argparse
|
|
|
|
expected_romstart = 0x30000
|
|
expected_moduleinfo_position = expected_romstart + 0x200
|
|
expected_moduleinfo_size = 0x18
|
|
# offsetof(module_end_address, module_info_t)
|
|
end_field_offset = 4
|
|
end_field_start = expected_moduleinfo_position - expected_romstart + end_field_offset
|
|
end_field_end = end_field_start + 4
|
|
|
|
|
|
def check(condition, message):
|
|
if not condition:
|
|
print(message, file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
p = argparse.ArgumentParser(description=__doc__)
|
|
p.add_argument("elf_in", help="Program in ELF form")
|
|
p.add_argument("bin_in", help="objdump'd ROM binary of elf_in")
|
|
p.add_argument("bin_out", help="File to write the modified bin to")
|
|
args = p.parse_args()
|
|
|
|
symbols = subprocess.check_output([
|
|
os.environ.get('NM', 'nm'),
|
|
"--format=posix",
|
|
"--print-size",
|
|
"--defined-only",
|
|
args.elf_in,
|
|
])
|
|
symbols = [line.split(' ') for line in symbols.decode('ascii').split('\n') if line]
|
|
position = {s[0]: int(s[2], 16) for s in symbols}
|
|
size = {s[0]: int(s[3], 16) for s in symbols if s[3]}
|
|
symtype = {s[0]: s[1] for s in symbols}
|
|
|
|
romstart = min(pos for (name, pos) in position.items() if symtype[name] not in '?A')
|
|
|
|
check(romstart == expected_romstart, "Defined symbols do not start at %#x" % expected_romstart)
|
|
|
|
check(position.get('particle_monofirmware_module_info') == expected_moduleinfo_position,
|
|
"""Struct particle_monofirmware_module_info not found at %#x but on %#x,
|
|
adjust the size of particle_monofirmware_padding to match""" %
|
|
(expected_moduleinfo_position, position.get('particle_monofirmware_module_info')))
|
|
check(size.get('particle_monofirmware_module_info') == expected_moduleinfo_size,
|
|
"Struct particle_monofirmware_module_info not of expected size %d" % expected_moduleinfo_size)
|
|
|
|
binary = bytearray(open(args.bin_in, 'rb').read())
|
|
|
|
indicated_start = int.from_bytes(binary[expected_moduleinfo_position - romstart:][:4], 'little')
|
|
check(romstart == indicated_start,
|
|
"particle_monofirmware_module_info.module_start does not point to the module start")
|
|
|
|
if 'particle_monofirmware_checksum' in position:
|
|
print("monifirmware-tool: Checksum symbol found, populating it.")
|
|
check(size.get('particle_monofirmware_checksum') == 4, "Checksum not of expected size 4")
|
|
|
|
checksum_until = position['particle_monofirmware_checksum'] - romstart
|
|
|
|
indicated_end = int.from_bytes(binary[end_field_start:end_field_end], 'little')
|
|
check(indicated_end == position['particle_monofirmware_checksum'],
|
|
"particle_monofirmware_module_info.module_end does not point to particle_monofirmware_checksum")
|
|
else:
|
|
print("monifirmware-tool: No checksum symbol found, appending the checksum to the binary.")
|
|
checksum_until = len(binary)
|
|
|
|
# Populating the length: When the whole binary (including the rom
|
|
# initialization block) is checksummed, the end address can't be populated
|
|
# from C because that would require evaluating `&_etext + (&_erelocate -
|
|
# &_srelocate)` in advance
|
|
binary[end_field_start:end_field_end] = (checksum_until + romstart).to_bytes(4, 'little')
|
|
|
|
checksum = zlib.crc32(binary[:checksum_until]).to_bytes(4, 'big')
|
|
binary[checksum_until:checksum_until + 4] = checksum
|
|
|
|
with open(args.bin_out, "wb") as o:
|
|
o.write(binary)
|