blob: 518674cf64a5d302ef9dbb8814a55e34e4187533 [file] [log] [blame]
Paul Burtonb1688ca2014-06-14 00:09:49 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2014 Imagination Technologies Ltd.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Paul Burtonb1688ca2014-06-14 00:09:49 +010015 */
16
17#include <errno.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
Vadim Bendeburyf44319c2014-11-04 16:17:33 -080021#include <string.h>
Paul Burtonb1688ca2014-06-14 00:09:49 +010022#include <sys/stat.h>
23#include <sys/types.h>
24
25struct bimg_header {
26 uint32_t magic;
27 uint16_t ver_major;
28 uint16_t ver_minor;
29 uint32_t data_size;
30 uint32_t entry_addr;
31 uint32_t flags;
32 uint32_t data_crc;
33 uint32_t crc;
34} __attribute__((packed));
35
36struct bimg_data_header {
37 uint32_t size;
38 uint32_t dest_addr;
Ionela Voinescua5457782014-10-31 17:21:41 +000039 uint16_t dummy;
Paul Burtonb1688ca2014-06-14 00:09:49 +010040 uint16_t crc;
41} __attribute__((packed));
42
Ionela Voinescua5457782014-10-31 17:21:41 +000043struct crc_t {
44 uint16_t (*crc_f)(uint16_t crc, void *void_buf, size_t size);
45 uint32_t crc_init;
46 uint16_t ver_major;
47 uint16_t ver_minor;
48};
49
50
Paul Burtonb1688ca2014-06-14 00:09:49 +010051#define BIMG_MAGIC /* y */ 0xabbadaba /* doo! */
52
53#define BIMG_OP_MASK (0xf << 0)
54#define BIMG_OP_EXEC_RETURN (0x1 << 0)
55#define BIMG_OP_EXEC_NO_RETURN (0x2 << 0)
56#define BIMG_DATA_CHECKSUM (0x1 << 4)
57
Vadim Bendeburyf44319c2014-11-04 16:17:33 -080058/* Typical use case for this utility. */
59#define BIMG_FLAGS (BIMG_OP_EXEC_NO_RETURN | BIMG_DATA_CHECKSUM)
60
Paul Burtonb1688ca2014-06-14 00:09:49 +010061#define MAX_RECORD_BYTES 0x8000
62
Ionela Voinescua5457782014-10-31 17:21:41 +000063#define CRC_16
Paul Burtonb1688ca2014-06-14 00:09:49 +010064
65#define error(msg...) fprintf(stderr, "ERROR: " msg)
66
67#define error_ret(ret, msg...) { \
68 error(msg); \
69 return ret; \
70}
71
Stefan Reinauerf0d0d912016-02-09 17:55:14 -080072#if defined(CRC_X25)
Paul Burtonb1688ca2014-06-14 00:09:49 +010073static uint16_t crc_x25(uint16_t crc, void *void_buf, size_t size)
74{
75 static const uint16_t crc_table[16] = {
76 0x0000, 0x1021, 0x2042, 0x3063,
77 0x4084, 0x50a5, 0x60c6, 0x70e7,
78 0x8108, 0x9129, 0xa14a, 0xb16b,
79 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
80 };
81 uint8_t *buf, data;
82
83 for (buf = void_buf; size; size--) {
84 data = *buf++;
85 crc = (crc << 4) ^ crc_table[((crc >> 12) ^ (data >> 4)) & 0xf];
86 crc = (crc << 4) ^ crc_table[((crc >> 12) ^ (data >> 0)) & 0xf];
87 }
88
89 return crc;
90}
Stefan Reinauerf0d0d912016-02-09 17:55:14 -080091#endif
Paul Burtonb1688ca2014-06-14 00:09:49 +010092
Stefan Reinauerf0d0d912016-02-09 17:55:14 -080093#if defined(CRC_16)
Ionela Voinescua5457782014-10-31 17:21:41 +000094static uint16_t crc_16(uint16_t crc, void *void_buf, size_t size)
95{
96 /*
97 * CRC table for the CRC-16.
98 * The poly is 0x8005 (x^16 + x^15 + x^2 + 1)
99 */
100 static const uint16_t crc16_table[256] = {
101 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
102 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
103 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
104 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
105 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
106 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
107 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
108 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
109 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
110 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
111 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
112 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
113 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
114 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
115 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
116 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
117 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
118 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
119 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
120 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
121 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
122 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
123 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
124 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
125 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
126 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
127 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
128 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
129 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
130 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
131 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
132 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
133 };
134 uint8_t *buf, data;
135
136 for (buf = void_buf; size; size--) {
137 data = *buf++;
138 crc = (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
139 }
140
141 return crc;
Ionela Voinescua5457782014-10-31 17:21:41 +0000142}
Stefan Reinauerf0d0d912016-02-09 17:55:14 -0800143#endif
Ionela Voinescua5457782014-10-31 17:21:41 +0000144
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800145static const struct crc_t crc_type = {
Ionela Voinescua5457782014-10-31 17:21:41 +0000146#if defined(CRC_16)
147 .crc_f = crc_16,
148 .crc_init = 0,
149 .ver_major = 2,
150 .ver_minor = 0
151#elif defined(CRC_X25)
152 .crc_f = crc_x25,
153 .crc_init = 0xffff,
154 .ver_major = 1,
155 .ver_minor = 0
156#endif
157};
158
Paul Burtonb1688ca2014-06-14 00:09:49 +0100159static int write_binary(FILE *out, FILE *in, struct bimg_header *hdr)
160{
161 static uint8_t file_buf[MAX_RECORD_BYTES];
Patrick Georgi2d119a32015-06-12 11:04:49 +0200162 struct bimg_data_header data_hdr = { 0 };
Paul Burtonb1688ca2014-06-14 00:09:49 +0100163 size_t n_written;
164
165 data_hdr.dest_addr = hdr->entry_addr;
166
Ionela Voinescua5457782014-10-31 17:21:41 +0000167 /*
168 * The read binary data has to be split in chunks of max 64KiB - 1 byte
169 * (SPI controller limitation). Each chunk will have its own header in
170 * order to respect the BIMG format.
171 */
Paul Burtonb1688ca2014-06-14 00:09:49 +0100172 while ((data_hdr.size = fread(file_buf, 1, sizeof(file_buf), in))) {
Ionela Voinescua5457782014-10-31 17:21:41 +0000173 data_hdr.crc = crc_type.crc_f(crc_type.crc_init, &data_hdr,
Paul Burtonb1688ca2014-06-14 00:09:49 +0100174 sizeof(data_hdr) - sizeof(data_hdr.crc));
175
176 if (fwrite(&data_hdr, sizeof(data_hdr), 1, out) != 1)
177 error_ret(-EIO, "Failed to write data header: %d\n",
178 errno);
179
180 n_written = fwrite(file_buf, 1, data_hdr.size, out);
181 if (n_written != data_hdr.size)
182 error_ret(-EIO, "Failed to write to output file: %d\n",
183 errno);
184
185 data_hdr.dest_addr += n_written;
186 hdr->data_size += sizeof(data_hdr) + n_written;
Ionela Voinescua5457782014-10-31 17:21:41 +0000187 hdr->data_crc = crc_type.crc_f(hdr->data_crc,
188 file_buf, n_written);
Paul Burtonb1688ca2014-06-14 00:09:49 +0100189 }
190
191 if (ferror(in))
192 error_ret(-EIO, "Failed to read input file\n");
193
194 return 0;
195}
196
197static int write_final(FILE *out, struct bimg_header *hdr)
198{
199 struct bimg_data_header data_hdr = {
200 .size = 0,
201 .dest_addr = ~0,
202 };
203
Ionela Voinescua5457782014-10-31 17:21:41 +0000204 data_hdr.crc = crc_type.crc_f(crc_type.crc_init, &data_hdr,
Paul Burtonb1688ca2014-06-14 00:09:49 +0100205 sizeof(data_hdr) - sizeof(data_hdr.crc));
206
207 if (fwrite(&data_hdr, sizeof(data_hdr), 1, out) != 1)
208 error_ret(-EIO, "Failed to write data header: %d\n", errno);
209
210 hdr->data_size += sizeof(data_hdr);
211
212 return 0;
213}
214
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800215static const char *help_message =
216 "Usage: bimgtool <input> [<output> <base-address>]\n"
217 "\n"
218 "This is a simple tool which generates and verifies boot images in\n"
219 "the BIMG format, used in systems designed by Imagination\n"
220 "Technologies, for example the Pistachio SoC. This version of the\n"
221 "tool works with BIMG images version %d.\n"
222 "\n"
223 " input: The binary file to be converted to a BIMG\n"
224 " or verified\n"
225 " output: The name of the output BIMG file\n"
226 " base-address: The address in memory at which you wish the "
227 " input binary to be loaded.\n";
228
Paul Burtonb1688ca2014-06-14 00:09:49 +0100229static void usage(FILE *f)
230{
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800231 fprintf(f, help_message, crc_type.ver_major);
232}
233
234static int verify_file(FILE *f)
235{
236 struct bimg_header file_header;
237 struct bimg_data_header data_header;
238 char *file_pointer;
239 char *file_data;
240 struct stat buf;
241 int data_size;
242 int fd = fileno(f);
243 uint32_t data_crc = crc_type.crc_init;
244 uint32_t crc_result;
245
246 if (fread(&file_header, 1, sizeof(struct bimg_header), f) !=
247 sizeof(struct bimg_header)) {
248 perror("Problems trying to read input file header\n");
249 return -1;
250 }
251
252 if (fstat(fd, &buf)) {
253 perror("Problems trying to stat input file\n");
254 return -1;
255 }
256
257 if (file_header.magic != BIMG_MAGIC) {
258 fprintf(stderr, "Wrong magic value %#x\n", file_header.magic);
259 return -1;
260 }
261
262 crc_result = crc_type.crc_f(crc_type.crc_init, &file_header,
263 sizeof(file_header) -
264 sizeof(file_header.crc));
265 if (file_header.crc != crc_result) {
266 fprintf(stderr, "File header CRC mismatch\n");
267 return -1;
268 }
269
270 if ((file_header.data_size + sizeof(struct bimg_header)) >
271 buf.st_size) {
Stefan Reinauer0544b312016-02-09 18:10:08 -0800272 fprintf(stderr, "Data size too big: %d > %zd\n",
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800273 file_header.data_size, buf.st_size);
274 return -1;
275 }
276
277 if (file_header.ver_major != crc_type.ver_major) {
278 fprintf(stderr, "Image version mismatch: %d\n",
279 file_header.ver_major);
280 return -1;
281 }
282
283 if ((file_header.flags & BIMG_FLAGS) != BIMG_FLAGS) {
284 fprintf(stderr, "Unexpected file header flags: %#x\n",
285 file_header.flags);
286 return -1;
287 }
288
289 if (file_header.ver_minor != crc_type.ver_minor) {
290 fprintf(stderr,
291 "Minor version mismatch: %d, will try anyways\n",
292 file_header.ver_minor);
293 }
294
295 data_size = file_header.data_size;
296 file_pointer = malloc(data_size);
297 if (!file_pointer) {
298 fprintf(stderr, "Failed to allocate %d bytes\n",
299 file_header.data_size);
300 return -1;
301 }
302
303 if (fread(file_pointer, 1, data_size, f) != data_size) {
304 fprintf(stderr, "Failed to read %d bytes\n", data_size);
305 free(file_pointer);
306 return -1;
307 }
308
309 file_data = file_pointer;
310 while (data_size > 0) {
311 memcpy(&data_header, file_data, sizeof(data_header));
312
313 /* Check the data block header integrity. */
314 crc_result = crc_type.crc_f(crc_type.crc_init, &data_header,
315 sizeof(data_header) -
316 sizeof(data_header.crc));
317 if (data_header.crc != crc_result) {
318 fprintf(stderr, "Data header CRC mismatch at %d\n",
319 file_header.data_size - data_size);
320 free(file_pointer);
321 return -1;
322 }
323
324 /*
325 * Add the block data to the CRC stream, the last block size
326 * will be zero.
327 */
328 file_data += sizeof(data_header);
329 data_crc = crc_type.crc_f(data_crc,
330 file_data, data_header.size);
331
332 data_size -= data_header.size + sizeof(data_header);
333 file_data += data_header.size;
334 }
335
336 if (data_size) {
337 fprintf(stderr, "File size mismatch\n");
338 free(file_pointer);
339 return -1;
340 }
341
342 if (data_crc != file_header.data_crc) {
343 fprintf(stderr, "File data CRC mismatch\n");
344 free(file_pointer);
345 return -1;
346 }
347
348 free(file_pointer);
349 return 0;
Paul Burtonb1688ca2014-06-14 00:09:49 +0100350}
351
352int main(int argc, char *argv[])
353{
354 const char *in_filename, *out_filename;
355 FILE *in_file, *out_file;
356 int err;
357 struct bimg_header hdr = {
358 .magic = BIMG_MAGIC,
Ionela Voinescua5457782014-10-31 17:21:41 +0000359 .ver_major = crc_type.ver_major,
360 .ver_minor = crc_type.ver_minor,
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800361 .flags = BIMG_FLAGS,
Ionela Voinescua5457782014-10-31 17:21:41 +0000362 .data_crc = crc_type.crc_init,
Paul Burtonb1688ca2014-06-14 00:09:49 +0100363 };
364
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800365 if ((argc != 4) && (argc != 2)) {
Paul Burtonb1688ca2014-06-14 00:09:49 +0100366 usage(stderr);
367 goto out_err;
368 }
369
370 in_filename = argv[1];
Paul Burtonb1688ca2014-06-14 00:09:49 +0100371
372 in_file = fopen(in_filename, "r");
373 if (!in_file) {
374 error("Failed to open input file '%s'\n", in_filename);
375 goto out_err;
376 }
377
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800378 if (argc == 2)
379 return verify_file(in_file);
380
381 out_filename = argv[2];
382 hdr.entry_addr = strtoul(argv[3], NULL, 16);
383
Paul Burtonb1688ca2014-06-14 00:09:49 +0100384 out_file = fopen(out_filename, "w");
385 if (!out_file) {
386 error("Failed to open output file '%s'\n", out_filename);
387 goto out_err_close_in;
388 }
389
390 if (fseek(out_file, sizeof(hdr), SEEK_SET)) {
391 error("Failed to seek past header: %d\n", errno);
392 goto out_err_close_out;
393 }
394
395 err = write_binary(out_file, in_file, &hdr);
396 if (err) {
397 error("Failed to write binary: %d\n", err);
398 goto out_err_close_out;
399 }
400
401 err = write_final(out_file, &hdr);
402 if (err) {
403 error("Failed to write final record: %d\n", err);
404 goto out_err_close_out;
405 }
406
Ionela Voinescua5457782014-10-31 17:21:41 +0000407 hdr.crc = crc_type.crc_f(crc_type.crc_init, &hdr,
408 sizeof(hdr) - sizeof(hdr.crc));
Paul Burtonb1688ca2014-06-14 00:09:49 +0100409
410 if (fseek(out_file, 0, SEEK_SET)) {
411 error("Failed to seek to header: %d\n", errno);
412 goto out_err_close_out;
413 }
414
415 if (fwrite(&hdr, sizeof(hdr), 1, out_file) != 1) {
416 error("Failed to write header: %d\n", errno);
417 goto out_err_close_out;
418 }
419
420 fclose(in_file);
421 fclose(out_file);
422 return EXIT_SUCCESS;
423
424out_err_close_out:
425 fclose(out_file);
426out_err_close_in:
427 fclose(in_file);
428out_err:
429 return EXIT_FAILURE;
430}