1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/boards/common/particle-mesh/monofirmware-tool.py

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)