1#!/usr/bin/env python3
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2017-2018, STMicroelectronics
5#
6import argparse
7import struct
8import mmap
9
10header_size = 256
11hdr_magic_number = 0x324D5453  # magic ='S' 'T' 'M' 0x32
12hdr_header_ver_variant = 0
13hdr_header_ver_minor = 0
14hdr_header_ver_major = 1
15hdr_version_number = 0
16hdr_option_flags = 1           # bit0=1 no signature
17hdr_edcsa_algo = 1
18
19
20def get_size(file):
21    file.seek(0, 2)        # End of the file
22    size = file.tell()
23    return size
24
25
26def stm32image_checksum(dest_fd, sizedest):
27    csum = 0
28    if sizedest < header_size:
29        return 0
30    dest_fd.seek(header_size, 0)
31    length = sizedest - header_size
32    while length > 0:
33        csum += ord(dest_fd.read(1))
34        length -= 1
35    return csum
36
37
38def stm32image_set_header(dest_fd, load, entry, bintype):
39    sizedest = get_size(dest_fd)
40
41    checksum = stm32image_checksum(dest_fd, sizedest)
42
43    dest_fd.seek(0, 0)
44
45    # Magic number
46    dest_fd.write(struct.pack('<I', hdr_magic_number))
47
48    # Image signature (empty)
49    dest_fd.write(b'\x00' * 64)
50
51    # Image checksum ... EDCSA algorithm
52    dest_fd.write(struct.pack('<IBBBBIIIIIIII',
53                  checksum,
54                  hdr_header_ver_variant,
55                  hdr_header_ver_minor,
56                  hdr_header_ver_major,
57                  0,
58                  sizedest - header_size,
59                  entry,
60                  0,
61                  load,
62                  0,
63                  hdr_version_number,
64                  hdr_option_flags,
65                  hdr_edcsa_algo))
66
67    # EDCSA public key (empty)
68    dest_fd.write(b'\x00' * 64)
69
70    # Padding
71    dest_fd.write(b'\x00' * 83)
72    dest_fd.write(struct.pack('<B', bintype))
73    dest_fd.close()
74
75
76def stm32image_create_header_file(source, dest, load, entry, bintype):
77    dest_fd = open(dest, 'w+b')
78    src_fd = open(source, 'rb')
79
80    dest_fd.write(b'\x00' * header_size)
81
82    sizesrc = get_size(src_fd)
83    if sizesrc > 0:
84        mmsrc = mmap.mmap(src_fd.fileno(), 0, access=mmap.ACCESS_READ)
85        dest_fd.write(mmsrc[:sizesrc])
86        mmsrc.close()
87
88    src_fd.close()
89
90    stm32image_set_header(dest_fd, load, entry, bintype)
91
92    dest_fd.close()
93
94
95def int_parse(str):
96    return int(str, 0)
97
98
99def get_args():
100    parser = argparse.ArgumentParser()
101    parser.add_argument('--source',
102                        required=True,
103                        help='Source file')
104
105    parser.add_argument('--dest',
106                        required=True,
107                        help='Destination file')
108
109    parser.add_argument('--load',
110                        required=True, type=int_parse,
111                        help='Load address')
112
113    parser.add_argument('--entry',
114                        required=True, type=int_parse,
115                        help='Entry point')
116
117    parser.add_argument('--bintype',
118                        required=True, type=int_parse,
119                        help='Binary identification')
120
121    return parser.parse_args()
122
123
124def main():
125    args = get_args()
126    source_file = args.source
127    destination_file = args.dest
128    load_address = args.load
129    entry_point = args.entry
130    binary_type = args.bintype
131
132    stm32image_create_header_file(source_file,
133                                  destination_file,
134                                  load_address,
135                                  entry_point,
136                                  binary_type)
137
138
139if __name__ == "__main__":
140    main()
141