reflow-oven-control-sw/stm-firmware/crc-patcher/crc_patch_elf.py

125 lines
3.8 KiB
Python
Raw Normal View History

2021-07-16 21:17:59 +02:00
#!/bin/python
"""
This script patches the CRC checksums into an existing ELF file.
For this, it searches the follwoing sections:
1) .text
2) .data
3) .ccmdata
4) .vectors
All sections MUST be a multiple of 4 bytes long
because the CRC calculation relies on whole 32 bit words.
The sections are extracted and the CRC is calculated for each section.
2021-07-16 21:17:59 +02:00
In the section .flashcrc, the script expects a single struct with the prototype:
struct flash_crcs {
uint32_t start_magic;
uint32_t crc_section_text;
uint32_t crc_section_data;
uint32_t crc_section_ccm_data;
uint32_t crc_section_vectors;
uint32_t end_magic;
};
It checks, if the start magic and end magic are set to the appropriate values and then
patches in the CRC values of the sections.
2021-07-16 21:17:59 +02:00
The magic values checked for are: 0xA8BE53F9 and 0xFFA582FF
"""
2021-07-16 21:17:59 +02:00
import sys
import struct
from elftools.elf.elffile import ELFFile
2021-07-16 21:17:59 +02:00
import crcmod
import crcmod.predefined
crc_calc = crcmod.predefined.mkCrcFun('crc-32-mpeg')
if len(sys.argv) < 2:
print("Usage:", sys.argv[0], ' <elf file>')
sys.exit(-1)
filename=sys.argv[1]
def section_calculate_crc(section):
"""
Calculate CRC of ELF file section
"""
2021-07-16 21:17:59 +02:00
data = bytearray(section.data())
be_data = bytearray([0 for k in range(0, len(data))])
# Rearrange data, because the STM controller sees it as 32 bit little endian words
for i in range(0, int(len(data)/4)):
be_data[i*4+0] = data[i*4+3]
be_data[i*4+1] = data[i*4+2]
be_data[i*4+2] = data[i*4+1]
be_data[i*4+3] = data[i*4+0]
return crc_calc(be_data)
def main():
"""
Main function. Patches CRCs into ELF file
"""
with open(filename, 'r+b') as elf_file:
elf = ELFFile(elf_file)
sections = {}
sections['.text'] = elf.get_section_by_name('.text')
sections['.data'] = elf.get_section_by_name('.data')
sections['.ccmdata'] = elf.get_section_by_name('.ccmdata')
sections['.vectors'] = elf.get_section_by_name('.vectors')
for key, sec in sections.items():
if sec is None:
print("Error! Section", key, "not found in ELF file!")
sys.exit(-1)
print('Found section', key, 'Size:',
sec.data_size, 'Type:', sec['sh_type'])
if sec['sh_type'] != 'SHT_PROGBITS':
print('Error! Section must be of type SHT_PROGBITS')
sys.exit(-1)
if sec.data_size % 4 != 0:
print("Section", key,
"has wrong size. Must be a multiple of 4 bytes!")
sys.exit(-1)
text_crc = section_calculate_crc(sections['.text'])
print('CRC of .text section:', hex(text_crc))
data_crc = section_calculate_crc(sections['.data'])
print('CRC of .data section:', hex(data_crc))
ccmdata_crc = section_calculate_crc(sections['.ccmdata'])
print('CRC of .ccmdata section:', hex(ccmdata_crc))
vextors_crc = section_calculate_crc(sections['.vectors'])
print('CRC of .vectors section:', hex(vextors_crc))
# Check the flashcrc section
flashcrc_sec = elf.get_section_by_name('.flashcrc')
if flashcrc_sec is None:
print('Section for flash CRC missing!')
2021-07-16 21:17:59 +02:00
sys.exit(-1)
if flashcrc_sec.data_size != 6*4:
print("Error: .flashcrc section has wrong size:",flashcrc_sec.data_size)
2021-07-16 21:17:59 +02:00
sys.exit(-1)
crc_sec_data = bytearray(flashcrc_sec.data())
magic1 = struct.unpack('<I'*1, bytes(crc_sec_data[0:4]))[0]
magic2 = struct.unpack('<I'*1, bytes(crc_sec_data[-4:]))[0]
print("CRC section magic values:", hex(magic1), hex(magic2))
if magic1 != 0xA8BE53F9 or magic2 != 0xFFA582FF:
print("Wrong magics in CRC section. Data misalignment?")
sys.exit(-2)
crc_sec_offset = flashcrc_sec['sh_offset']
print('CRC section ELF file offset:', hex(crc_sec_offset))
crc_sec_data[4:8] = struct.pack('<I',text_crc)
crc_sec_data[8:12] = struct.pack('<I',data_crc)
crc_sec_data[12:16] = struct.pack('<I',ccmdata_crc)
crc_sec_data[16:20] = struct.pack('<I',vextors_crc)
elf_file.seek(crc_sec_offset)
elf_file.write(crc_sec_data)
print('CRCs patched successfully')
if __name__ == '__main__':
main()