1 /*
2 * Copyright (c) 2017-2026, STMicroelectronics - All Rights Reserved
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <asm/byteorder.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/mman.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18
19 /* Magic = 'S' 'T' 'M' 0x32 */
20 #define HEADER_MAGIC __be32_to_cpu(0x53544D32)
21 #define VER_MAJOR 2
22 #define VER_MINOR 1
23 #define VER_VARIANT 0
24 #define HEADER_VERSION_V1 0x1
25 #define HEADER_VERSION_V2 0x2
26 #define HEADER_SUBVERSION_VX_3 0x3
27 #define PADDING_HEADER_MAGIC __be32_to_cpu(0x5354FFFF)
28 #define PADDING_HEADER_FLAG (1 << 31)
29 #define PADDING_HEADER_LENGTH 0x180
30 #define PADDING_HEADER_LENGTH_V23 0x1A0
31
32 struct stm32_header_v1 {
33 uint32_t magic_number;
34 uint8_t image_signature[64];
35 uint32_t image_checksum;
36 uint8_t header_version[4];
37 uint32_t image_length;
38 uint32_t image_entry_point;
39 uint32_t reserved1;
40 uint32_t load_address;
41 uint32_t reserved2;
42 uint32_t version_number;
43 uint32_t option_flags;
44 uint32_t ecdsa_algorithm;
45 uint8_t ecdsa_public_key[64];
46 uint8_t padding[83];
47 uint8_t binary_type;
48 };
49
50 struct stm32_header_v2 {
51 uint32_t magic_number;
52 uint8_t image_signature[64];
53 uint32_t image_checksum;
54 uint8_t header_version[4];
55 uint32_t image_length;
56 uint32_t image_entry_point;
57 uint32_t reserved1;
58 uint32_t load_address;
59 uint32_t reserved2;
60 uint32_t version_number;
61 uint32_t extension_flags;
62 uint32_t extension_headers_length;
63 uint32_t binary_type;
64 uint8_t padding[16];
65 uint32_t extension_header_type;
66 uint32_t extension_header_length;
67 uint8_t extension_padding[376];
68 };
69
70 struct stm32_header_v23 {
71 uint32_t magic_number;
72 uint8_t image_signature[96];
73 uint32_t image_checksum;
74 uint8_t header_version[4];
75 uint32_t image_length;
76 uint32_t image_entry_point;
77 uint32_t reserved1;
78 uint32_t load_address;
79 uint32_t reserved2;
80 uint32_t version_number;
81 uint32_t extension_flags;
82 uint32_t extension_headers_length;
83 uint32_t binary_type;
84 uint8_t padding[8];
85 uint32_t non_secure_payload_length;
86 uint32_t non_secure_payload_hash;
87 uint32_t extension_header_type;
88 uint32_t extension_header_length;
89 uint8_t extension_padding[408];
90 };
91
stm32image_default_header(void * ptr,uint32_t minor)92 static void stm32image_default_header(void *ptr, uint32_t minor)
93 {
94 struct stm32_header_v1 *header = (struct stm32_header_v1 *)ptr;
95 struct stm32_header_v23 *header_v23 = (struct stm32_header_v23 *)ptr;
96
97 if (header == NULL) {
98 return;
99 }
100
101 header->magic_number = HEADER_MAGIC;
102 if (minor == HEADER_SUBVERSION_VX_3) {
103 header_v23->version_number = __cpu_to_le32(0);
104 } else {
105 header->version_number = __cpu_to_le32(0);
106 }
107 }
108
stm32image_checksum(void * start,uint32_t len,uint32_t header_size)109 static uint32_t stm32image_checksum(void *start, uint32_t len,
110 uint32_t header_size)
111 {
112 uint32_t csum = 0U;
113 uint8_t *p;
114
115 if (len < header_size) {
116 return 0U;
117 }
118
119 p = (uint8_t *)start + header_size;
120 len -= header_size;
121
122 while (len > 0U) {
123 csum += *p;
124 p++;
125 len--;
126 }
127
128 return csum;
129 }
130
stm32image_print_header(const void * ptr)131 static void stm32image_print_header(const void *ptr)
132 {
133 struct stm32_header_v1 *stm32hdr = (struct stm32_header_v1 *)ptr;
134 struct stm32_header_v2 *stm32hdr_v2 = (struct stm32_header_v2 *)ptr;
135 struct stm32_header_v23 *stm32hdr_v23 = (struct stm32_header_v23 *)ptr;
136
137 if (stm32hdr_v23->header_version[VER_MINOR] == HEADER_SUBVERSION_VX_3) {
138 printf("Image Type : ST Microelectronics STM32 V%d.%d\n",
139 stm32hdr_v23->header_version[VER_MAJOR],
140 stm32hdr_v23->header_version[VER_MINOR]);
141 printf("Image Size : %lu bytes\n",
142 (unsigned long)__le32_to_cpu(stm32hdr_v23->image_length));
143 printf("Image Load : 0x%08x\n",
144 __le32_to_cpu(stm32hdr_v23->load_address));
145 printf("Entry Point : 0x%08x\n",
146 __le32_to_cpu(stm32hdr_v23->image_entry_point));
147 printf("Checksum : 0x%08x\n",
148 __le32_to_cpu(stm32hdr_v23->image_checksum));
149 printf("Extension : 0x%08x\n",
150 __le32_to_cpu(stm32hdr_v23->extension_flags));
151 printf("Version : 0x%08x\n",
152 __le32_to_cpu(stm32hdr_v23->version_number));
153 } else {
154 printf("Image Type : ST Microelectronics STM32 V%d.%d\n",
155 stm32hdr->header_version[VER_MAJOR],
156 stm32hdr->header_version[VER_MINOR]);
157 printf("Image Size : %lu bytes\n",
158 (unsigned long)__le32_to_cpu(stm32hdr->image_length));
159 printf("Image Load : 0x%08x\n",
160 __le32_to_cpu(stm32hdr->load_address));
161 printf("Entry Point : 0x%08x\n",
162 __le32_to_cpu(stm32hdr->image_entry_point));
163 printf("Checksum : 0x%08x\n",
164 __le32_to_cpu(stm32hdr->image_checksum));
165
166 switch (stm32hdr->header_version[VER_MAJOR]) {
167 case HEADER_VERSION_V1:
168 printf("Option : 0x%08x\n",
169 __le32_to_cpu(stm32hdr->option_flags));
170 break;
171
172 case HEADER_VERSION_V2:
173 printf("Extension : 0x%08x\n",
174 __le32_to_cpu(stm32hdr_v2->extension_flags));
175 break;
176
177 default:
178 printf("Incorrect header version\n");
179 }
180
181 printf("Version : 0x%08x\n",
182 __le32_to_cpu(stm32hdr->version_number));
183 }
184 }
185
stm32image_set_header(void * ptr,struct stat * sbuf,int ifd,uint32_t loadaddr,uint32_t ep,uint32_t ver,uint32_t major,uint32_t minor,uint32_t binary_type,uint32_t header_size)186 static int stm32image_set_header(void *ptr, struct stat *sbuf, int ifd,
187 uint32_t loadaddr, uint32_t ep, uint32_t ver,
188 uint32_t major, uint32_t minor,
189 uint32_t binary_type, uint32_t header_size)
190 {
191 struct stm32_header_v1 *stm32hdr = (struct stm32_header_v1 *)ptr;
192 struct stm32_header_v2 *stm32hdr_v2 = (struct stm32_header_v2 *)ptr;
193 struct stm32_header_v23 *stm32hdr_v23 = (struct stm32_header_v23 *)ptr;
194 uint32_t ext_size = 0U;
195 uint32_t ext_flags = 0U;
196
197 stm32image_default_header(ptr, minor);
198
199 if (minor == HEADER_SUBVERSION_VX_3) {
200 stm32hdr_v23->header_version[VER_MAJOR] = major;
201 stm32hdr_v23->header_version[VER_MINOR] = minor;
202 stm32hdr_v23->load_address = __cpu_to_le32(loadaddr);
203 stm32hdr_v23->image_entry_point = __cpu_to_le32(ep);
204 stm32hdr_v23->image_length = __cpu_to_le32((uint32_t)sbuf->st_size -
205 header_size);
206 stm32hdr_v23->image_checksum =
207 __cpu_to_le32(stm32image_checksum(ptr, sbuf->st_size,
208 header_size));
209 stm32hdr_v23->binary_type = binary_type;
210 ext_size += PADDING_HEADER_LENGTH_V23;
211 ext_flags |= PADDING_HEADER_FLAG;
212 stm32hdr_v23->extension_flags =
213 __cpu_to_le32(ext_flags);
214 stm32hdr_v23->extension_headers_length =
215 __cpu_to_le32(ext_size);
216 stm32hdr_v23->extension_header_type = PADDING_HEADER_MAGIC;
217 stm32hdr_v23->extension_header_length =
218 __cpu_to_le32(PADDING_HEADER_LENGTH_V23);
219 stm32hdr_v23->version_number = __cpu_to_le32(ver);
220 } else {
221 stm32hdr->header_version[VER_MAJOR] = major;
222 stm32hdr->header_version[VER_MINOR] = minor;
223 stm32hdr->load_address = __cpu_to_le32(loadaddr);
224 stm32hdr->image_entry_point = __cpu_to_le32(ep);
225 stm32hdr->image_length = __cpu_to_le32((uint32_t)sbuf->st_size -
226 header_size);
227 stm32hdr->image_checksum =
228 __cpu_to_le32(stm32image_checksum(ptr, sbuf->st_size,
229 header_size));
230
231 switch (stm32hdr->header_version[VER_MAJOR]) {
232 case HEADER_VERSION_V1:
233 /* Default option for header v1 : bit0 => no signature */
234 stm32hdr->option_flags = __cpu_to_le32(0x00000001);
235 stm32hdr->ecdsa_algorithm = __cpu_to_le32(1);
236 stm32hdr->binary_type = (uint8_t)binary_type;
237 break;
238
239 case HEADER_VERSION_V2:
240 stm32hdr_v2->binary_type = binary_type;
241 ext_size += PADDING_HEADER_LENGTH;
242 ext_flags |= PADDING_HEADER_FLAG;
243 stm32hdr_v2->extension_flags =
244 __cpu_to_le32(ext_flags);
245 stm32hdr_v2->extension_headers_length =
246 __cpu_to_le32(ext_size);
247 stm32hdr_v2->extension_header_type = PADDING_HEADER_MAGIC;
248 stm32hdr_v2->extension_header_length =
249 __cpu_to_le32(PADDING_HEADER_LENGTH);
250 break;
251
252 default:
253 return -1;
254 }
255
256 stm32hdr->version_number = __cpu_to_le32(ver);
257 }
258
259 return 0;
260 }
261
stm32image_create_header_file(char * srcname,char * destname,uint32_t loadaddr,uint32_t entry,uint32_t version,uint32_t major,uint32_t minor,uint32_t binary_type)262 static int stm32image_create_header_file(char *srcname, char *destname,
263 uint32_t loadaddr, uint32_t entry,
264 uint32_t version, uint32_t major,
265 uint32_t minor, uint32_t binary_type)
266 {
267 int src_fd = -1, dest_fd = -1;
268 struct stat sbuf;
269 unsigned char *ptr = NULL;
270 void *stm32image_header;
271 size_t map_size = 0U, header_size = 0U;
272 ssize_t wr;
273 int ret = -1;
274
275 dest_fd = open(destname, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666);
276 if (dest_fd == -1) {
277 fprintf(stderr, "Can't open %s: %s\n", destname,
278 strerror(errno));
279 return -1;
280 }
281
282 src_fd = open(srcname, O_RDONLY);
283 if (src_fd == -1) {
284 fprintf(stderr, "Can't open %s: %s\n", srcname,
285 strerror(errno));
286 goto out;
287 }
288
289 /* Source file section */
290 if (fstat(src_fd, &sbuf) < 0) {
291 goto out;
292 }
293
294 if (sbuf.st_size < 0) {
295 fprintf(stderr, "Invalid file size for %s\n", srcname);
296 goto out;
297 }
298
299 map_size = (size_t)sbuf.st_size;
300
301 ptr = mmap(NULL, map_size, PROT_READ, MAP_SHARED, src_fd, 0);
302 if (ptr == MAP_FAILED) {
303 fprintf(stderr, "Can't read %s\n", srcname);
304 ptr = NULL;
305 map_size = 0U;
306 goto out;
307 }
308
309 if (minor == HEADER_SUBVERSION_VX_3) {
310 header_size = sizeof(struct stm32_header_v23);
311 stm32image_header = malloc(header_size);
312 } else {
313 switch (major) {
314 case HEADER_VERSION_V1:
315 header_size = sizeof(struct stm32_header_v1);
316 stm32image_header = malloc(header_size);
317 break;
318
319 case HEADER_VERSION_V2:
320 header_size = sizeof(struct stm32_header_v2);
321 stm32image_header = malloc(header_size);
322 break;
323
324 default:
325 fprintf(stderr, "Unsupported header version (major=%u, minor=%u)\n",
326 major, minor);
327 goto out;
328 }
329 }
330
331 if (stm32image_header == NULL) {
332 fprintf(stderr, "malloc failed for header\n");
333 goto out;
334 }
335
336 memset(stm32image_header, 0, header_size);
337
338 wr = write(dest_fd, stm32image_header, header_size);
339 if ((wr < 0) || ((size_t)wr != header_size)) {
340 fprintf(stderr, "Write error %s (header): %s\n",
341 destname, strerror(errno));
342 free(stm32image_header);
343 goto out;
344 }
345
346 free(stm32image_header);
347
348 wr = write(dest_fd, ptr, map_size);
349 if ((wr < 0) || ((size_t)wr != map_size)) {
350 fprintf(stderr, "Write error %s (payload): %s\n",
351 destname, strerror(errno));
352 goto out;
353 }
354
355 if ((ptr != NULL) && (map_size > 0U)) {
356 munmap(ptr, map_size);
357 ptr = NULL;
358 map_size = 0U;
359 }
360
361 if (src_fd >= 0) {
362 close(src_fd);
363 src_fd = -1;
364 }
365
366 /* Dest file section */
367 if (fstat(dest_fd, &sbuf) < 0) {
368 goto out;
369 }
370
371 if (sbuf.st_size < 0) {
372 fprintf(stderr, "Invalid dest file size for %s\n", destname);
373 goto out;
374 }
375
376 map_size = (size_t)sbuf.st_size;
377
378 ptr = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED,
379 dest_fd, 0);
380 if (ptr == MAP_FAILED) {
381 fprintf(stderr, "Can't write %s\n", destname);
382 ptr = NULL;
383 map_size = 0U;
384 goto out;
385 }
386
387 if (stm32image_set_header(ptr, &sbuf, dest_fd, loadaddr,
388 entry, version, major, minor,
389 binary_type, header_size) != 0) {
390 fprintf(stderr, "stm32image_set_header failed\n");
391 goto out;
392 }
393
394 stm32image_print_header(ptr);
395 ret = 0;
396
397 out:
398 if ((ptr != NULL) && (map_size > 0U)) {
399 munmap(ptr, map_size);
400 }
401 if (src_fd >= 0) {
402 close(src_fd);
403 }
404 if (dest_fd >= 0) {
405 close(dest_fd);
406 }
407
408 return ret;
409 }
410
main(int argc,char * argv[])411 int main(int argc, char *argv[])
412 {
413 int opt;
414 int loadaddr = -1;
415 int entry = -1;
416 int err = 0;
417 int version = 0;
418 int binary_type = -1;
419 int major = HEADER_VERSION_V2;
420 int minor = 0;
421 char *dest = NULL;
422 char *src = NULL;
423
424 while ((opt = getopt(argc, argv, ":b:s:d:l:e:v:m:n:")) != -1) {
425 switch (opt) {
426 case 'b':
427 binary_type = strtol(optarg, NULL, 0);
428 break;
429 case 's':
430 src = optarg;
431 break;
432 case 'd':
433 dest = optarg;
434 break;
435 case 'l':
436 loadaddr = strtol(optarg, NULL, 0);
437 break;
438 case 'e':
439 entry = strtol(optarg, NULL, 0);
440 break;
441 case 'v':
442 version = strtol(optarg, NULL, 0);
443 break;
444 case 'm':
445 major = strtol(optarg, NULL, 0);
446 break;
447 case 'n':
448 minor = strtol(optarg, NULL, 0);
449 break;
450 default:
451 fprintf(stderr,
452 "Usage : %s [-s srcfile] [-d destfile] [-l loadaddr] [-e entry_point] [-m major] [-n minor] [-b binary_type]\n",
453 argv[0]);
454 return -1;
455 }
456 }
457
458 if (src == NULL) {
459 fprintf(stderr, "Missing -s option\n");
460 return -1;
461 }
462
463 if (dest == NULL) {
464 fprintf(stderr, "Missing -d option\n");
465 return -1;
466 }
467
468 if (loadaddr == -1) {
469 fprintf(stderr, "Missing -l option\n");
470 return -1;
471 }
472
473 if (entry == -1) {
474 fprintf(stderr, "Missing -e option\n");
475 return -1;
476 }
477
478 if (binary_type == -1) {
479 fprintf(stderr, "Missing -b option\n");
480 return -1;
481 }
482
483 err = stm32image_create_header_file(src, dest, loadaddr,
484 entry, version, major, minor,
485 binary_type);
486
487 return err;
488 }
489