blob: 4e8fb3feed364b88bbe751c725be69837e95230f [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
72static uint16_t crc_x25(uint16_t crc, void *void_buf, size_t size)
73{
74 static const uint16_t crc_table[16] = {
75 0x0000, 0x1021, 0x2042, 0x3063,
76 0x4084, 0x50a5, 0x60c6, 0x70e7,
77 0x8108, 0x9129, 0xa14a, 0xb16b,
78 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
79 };
80 uint8_t *buf, data;
81
82 for (buf = void_buf; size; size--) {
83 data = *buf++;
84 crc = (crc << 4) ^ crc_table[((crc >> 12) ^ (data >> 4)) & 0xf];
85 crc = (crc << 4) ^ crc_table[((crc >> 12) ^ (data >> 0)) & 0xf];
86 }
87
88 return crc;
89}
90
Ionela Voinescua5457782014-10-31 17:21:41 +000091static uint16_t crc_16(uint16_t crc, void *void_buf, size_t size)
92{
93 /*
94 * CRC table for the CRC-16.
95 * The poly is 0x8005 (x^16 + x^15 + x^2 + 1)
96 */
97 static const uint16_t crc16_table[256] = {
98 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
99 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
100 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
101 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
102 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
103 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
104 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
105 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
106 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
107 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
108 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
109 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
110 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
111 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
112 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
113 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
114 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
115 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
116 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
117 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
118 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
119 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
120 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
121 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
122 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
123 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
124 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
125 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
126 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
127 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
128 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
129 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
130 };
131 uint8_t *buf, data;
132
133 for (buf = void_buf; size; size--) {
134 data = *buf++;
135 crc = (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
136 }
137
138 return crc;
139
140}
141
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800142static const struct crc_t crc_type = {
Ionela Voinescua5457782014-10-31 17:21:41 +0000143#if defined(CRC_16)
144 .crc_f = crc_16,
145 .crc_init = 0,
146 .ver_major = 2,
147 .ver_minor = 0
148#elif defined(CRC_X25)
149 .crc_f = crc_x25,
150 .crc_init = 0xffff,
151 .ver_major = 1,
152 .ver_minor = 0
153#endif
154};
155
Paul Burtonb1688ca2014-06-14 00:09:49 +0100156static int write_binary(FILE *out, FILE *in, struct bimg_header *hdr)
157{
158 static uint8_t file_buf[MAX_RECORD_BYTES];
Patrick Georgi2d119a32015-06-12 11:04:49 +0200159 struct bimg_data_header data_hdr = { 0 };
Paul Burtonb1688ca2014-06-14 00:09:49 +0100160 size_t n_written;
161
162 data_hdr.dest_addr = hdr->entry_addr;
163
Ionela Voinescua5457782014-10-31 17:21:41 +0000164 /*
165 * The read binary data has to be split in chunks of max 64KiB - 1 byte
166 * (SPI controller limitation). Each chunk will have its own header in
167 * order to respect the BIMG format.
168 */
Paul Burtonb1688ca2014-06-14 00:09:49 +0100169 while ((data_hdr.size = fread(file_buf, 1, sizeof(file_buf), in))) {
Ionela Voinescua5457782014-10-31 17:21:41 +0000170 data_hdr.crc = crc_type.crc_f(crc_type.crc_init, &data_hdr,
Paul Burtonb1688ca2014-06-14 00:09:49 +0100171 sizeof(data_hdr) - sizeof(data_hdr.crc));
172
173 if (fwrite(&data_hdr, sizeof(data_hdr), 1, out) != 1)
174 error_ret(-EIO, "Failed to write data header: %d\n",
175 errno);
176
177 n_written = fwrite(file_buf, 1, data_hdr.size, out);
178 if (n_written != data_hdr.size)
179 error_ret(-EIO, "Failed to write to output file: %d\n",
180 errno);
181
182 data_hdr.dest_addr += n_written;
183 hdr->data_size += sizeof(data_hdr) + n_written;
Ionela Voinescua5457782014-10-31 17:21:41 +0000184 hdr->data_crc = crc_type.crc_f(hdr->data_crc,
185 file_buf, n_written);
Paul Burtonb1688ca2014-06-14 00:09:49 +0100186 }
187
188 if (ferror(in))
189 error_ret(-EIO, "Failed to read input file\n");
190
191 return 0;
192}
193
194static int write_final(FILE *out, struct bimg_header *hdr)
195{
196 struct bimg_data_header data_hdr = {
197 .size = 0,
198 .dest_addr = ~0,
199 };
200
Ionela Voinescua5457782014-10-31 17:21:41 +0000201 data_hdr.crc = crc_type.crc_f(crc_type.crc_init, &data_hdr,
Paul Burtonb1688ca2014-06-14 00:09:49 +0100202 sizeof(data_hdr) - sizeof(data_hdr.crc));
203
204 if (fwrite(&data_hdr, sizeof(data_hdr), 1, out) != 1)
205 error_ret(-EIO, "Failed to write data header: %d\n", errno);
206
207 hdr->data_size += sizeof(data_hdr);
208
209 return 0;
210}
211
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800212static const char *help_message =
213 "Usage: bimgtool <input> [<output> <base-address>]\n"
214 "\n"
215 "This is a simple tool which generates and verifies boot images in\n"
216 "the BIMG format, used in systems designed by Imagination\n"
217 "Technologies, for example the Pistachio SoC. This version of the\n"
218 "tool works with BIMG images version %d.\n"
219 "\n"
220 " input: The binary file to be converted to a BIMG\n"
221 " or verified\n"
222 " output: The name of the output BIMG file\n"
223 " base-address: The address in memory at which you wish the "
224 " input binary to be loaded.\n";
225
Paul Burtonb1688ca2014-06-14 00:09:49 +0100226static void usage(FILE *f)
227{
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800228 fprintf(f, help_message, crc_type.ver_major);
229}
230
231static int verify_file(FILE *f)
232{
233 struct bimg_header file_header;
234 struct bimg_data_header data_header;
235 char *file_pointer;
236 char *file_data;
237 struct stat buf;
238 int data_size;
239 int fd = fileno(f);
240 uint32_t data_crc = crc_type.crc_init;
241 uint32_t crc_result;
242
243 if (fread(&file_header, 1, sizeof(struct bimg_header), f) !=
244 sizeof(struct bimg_header)) {
245 perror("Problems trying to read input file header\n");
246 return -1;
247 }
248
249 if (fstat(fd, &buf)) {
250 perror("Problems trying to stat input file\n");
251 return -1;
252 }
253
254 if (file_header.magic != BIMG_MAGIC) {
255 fprintf(stderr, "Wrong magic value %#x\n", file_header.magic);
256 return -1;
257 }
258
259 crc_result = crc_type.crc_f(crc_type.crc_init, &file_header,
260 sizeof(file_header) -
261 sizeof(file_header.crc));
262 if (file_header.crc != crc_result) {
263 fprintf(stderr, "File header CRC mismatch\n");
264 return -1;
265 }
266
267 if ((file_header.data_size + sizeof(struct bimg_header)) >
268 buf.st_size) {
269 fprintf(stderr, "Data size too big: %d > %d\n",
270 file_header.data_size, buf.st_size);
271 return -1;
272 }
273
274 if (file_header.ver_major != crc_type.ver_major) {
275 fprintf(stderr, "Image version mismatch: %d\n",
276 file_header.ver_major);
277 return -1;
278 }
279
280 if ((file_header.flags & BIMG_FLAGS) != BIMG_FLAGS) {
281 fprintf(stderr, "Unexpected file header flags: %#x\n",
282 file_header.flags);
283 return -1;
284 }
285
286 if (file_header.ver_minor != crc_type.ver_minor) {
287 fprintf(stderr,
288 "Minor version mismatch: %d, will try anyways\n",
289 file_header.ver_minor);
290 }
291
292 data_size = file_header.data_size;
293 file_pointer = malloc(data_size);
294 if (!file_pointer) {
295 fprintf(stderr, "Failed to allocate %d bytes\n",
296 file_header.data_size);
297 return -1;
298 }
299
300 if (fread(file_pointer, 1, data_size, f) != data_size) {
301 fprintf(stderr, "Failed to read %d bytes\n", data_size);
302 free(file_pointer);
303 return -1;
304 }
305
306 file_data = file_pointer;
307 while (data_size > 0) {
308 memcpy(&data_header, file_data, sizeof(data_header));
309
310 /* Check the data block header integrity. */
311 crc_result = crc_type.crc_f(crc_type.crc_init, &data_header,
312 sizeof(data_header) -
313 sizeof(data_header.crc));
314 if (data_header.crc != crc_result) {
315 fprintf(stderr, "Data header CRC mismatch at %d\n",
316 file_header.data_size - data_size);
317 free(file_pointer);
318 return -1;
319 }
320
321 /*
322 * Add the block data to the CRC stream, the last block size
323 * will be zero.
324 */
325 file_data += sizeof(data_header);
326 data_crc = crc_type.crc_f(data_crc,
327 file_data, data_header.size);
328
329 data_size -= data_header.size + sizeof(data_header);
330 file_data += data_header.size;
331 }
332
333 if (data_size) {
334 fprintf(stderr, "File size mismatch\n");
335 free(file_pointer);
336 return -1;
337 }
338
339 if (data_crc != file_header.data_crc) {
340 fprintf(stderr, "File data CRC mismatch\n");
341 free(file_pointer);
342 return -1;
343 }
344
345 free(file_pointer);
346 return 0;
Paul Burtonb1688ca2014-06-14 00:09:49 +0100347}
348
349int main(int argc, char *argv[])
350{
351 const char *in_filename, *out_filename;
352 FILE *in_file, *out_file;
353 int err;
354 struct bimg_header hdr = {
355 .magic = BIMG_MAGIC,
Ionela Voinescua5457782014-10-31 17:21:41 +0000356 .ver_major = crc_type.ver_major,
357 .ver_minor = crc_type.ver_minor,
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800358 .flags = BIMG_FLAGS,
Ionela Voinescua5457782014-10-31 17:21:41 +0000359 .data_crc = crc_type.crc_init,
Paul Burtonb1688ca2014-06-14 00:09:49 +0100360 };
361
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800362 if ((argc != 4) && (argc != 2)) {
Paul Burtonb1688ca2014-06-14 00:09:49 +0100363 usage(stderr);
364 goto out_err;
365 }
366
367 in_filename = argv[1];
Paul Burtonb1688ca2014-06-14 00:09:49 +0100368
369 in_file = fopen(in_filename, "r");
370 if (!in_file) {
371 error("Failed to open input file '%s'\n", in_filename);
372 goto out_err;
373 }
374
Vadim Bendeburyf44319c2014-11-04 16:17:33 -0800375 if (argc == 2)
376 return verify_file(in_file);
377
378 out_filename = argv[2];
379 hdr.entry_addr = strtoul(argv[3], NULL, 16);
380
Paul Burtonb1688ca2014-06-14 00:09:49 +0100381 out_file = fopen(out_filename, "w");
382 if (!out_file) {
383 error("Failed to open output file '%s'\n", out_filename);
384 goto out_err_close_in;
385 }
386
387 if (fseek(out_file, sizeof(hdr), SEEK_SET)) {
388 error("Failed to seek past header: %d\n", errno);
389 goto out_err_close_out;
390 }
391
392 err = write_binary(out_file, in_file, &hdr);
393 if (err) {
394 error("Failed to write binary: %d\n", err);
395 goto out_err_close_out;
396 }
397
398 err = write_final(out_file, &hdr);
399 if (err) {
400 error("Failed to write final record: %d\n", err);
401 goto out_err_close_out;
402 }
403
Ionela Voinescua5457782014-10-31 17:21:41 +0000404 hdr.crc = crc_type.crc_f(crc_type.crc_init, &hdr,
405 sizeof(hdr) - sizeof(hdr.crc));
Paul Burtonb1688ca2014-06-14 00:09:49 +0100406
407 if (fseek(out_file, 0, SEEK_SET)) {
408 error("Failed to seek to header: %d\n", errno);
409 goto out_err_close_out;
410 }
411
412 if (fwrite(&hdr, sizeof(hdr), 1, out_file) != 1) {
413 error("Failed to write header: %d\n", errno);
414 goto out_err_close_out;
415 }
416
417 fclose(in_file);
418 fclose(out_file);
419 return EXIT_SUCCESS;
420
421out_err_close_out:
422 fclose(out_file);
423out_err_close_in:
424 fclose(in_file);
425out_err:
426 return EXIT_FAILURE;
427}