summaryrefslogtreecommitdiff
path: root/tools/pad_checksum.py
blob: d3017568264c3bc53ef3babc3c89693154a2f497 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/env python3

import argparse
import binascii
import struct
import sys


def any_int(x):
    try:
        return int(x, 0)
    except:
        raise argparse.ArgumentTypeError("expected an integer, not '{!r}'".format(x))


def bitrev(x, width):
    return int("{:0{w}b}".format(x, w=width)[::-1], 2)


parser = argparse.ArgumentParser()
parser.add_argument("ifile", help="Input file (binary)")
parser.add_argument("ofile", help="Output file (assembly)")
parser.add_argument("-p", "--pad", help="Padded size (bytes), including 4-byte checksum, default 256",
                    type=any_int, default=256)
parser.add_argument("-s", "--seed", help="Checksum seed value, default 0",
                    type=any_int, default=0)
args = parser.parse_args()

try:
    idata = open(args.ifile, "rb").read()
except:
    sys.exit("Could not open input file '{}'".format(args.ifile))

if len(idata) > args.pad - 4:
    sys.exit("Input file size ({} bytes) too large for final size ({} bytes)".format(len(idata), args.pad))

idata_padded = idata + bytes(args.pad - 4 - len(idata))

# Our bootrom CRC32 is slightly bass-ackward but it's best to work around for now (FIXME)
# 100% worth it to save two Thumb instructions
checksum = bitrev(
    (binascii.crc32(bytes(bitrev(b, 8) for b in idata_padded), args.seed ^ 0xffffffff) ^ 0xffffffff) & 0xffffffff, 32)
odata = idata_padded + struct.pack("<L", checksum)

try:
    with open(args.ofile, "w") as ofile:
        ofile.write("// Padded and checksummed version of: {}\n\n".format(args.ifile))
        ofile.write(".cpu cortex-m0plus\n")
        ofile.write(".thumb\n\n")
        ofile.write(".section .boot2, \"ax\"\n\n")
        for offs in range(0, len(odata), 16):
            chunk = odata[offs:min(offs + 16, len(odata))]
            ofile.write(".byte {}\n".format(", ".join("0x{:02x}".format(b) for b in chunk)))
except:
    sys.exit("Could not open output file '{}'".format(args.ofile))