2 * This file is part of the coreboot project.
4 * Copyright 2014 Imagination Technologies Ltd.
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
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.
23 #include <sys/types.h>
34 } __attribute__((packed
));
36 struct bimg_data_header
{
41 } __attribute__((packed
));
44 uint16_t (*crc_f
)(uint16_t crc
, void *void_buf
, size_t size
);
51 #define BIMG_MAGIC /* y */ 0xabbadaba /* doo! */
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)
58 /* Typical use case for this utility. */
59 #define BIMG_FLAGS (BIMG_OP_EXEC_NO_RETURN | BIMG_DATA_CHECKSUM)
61 #define MAX_RECORD_BYTES 0x8000
65 #define error(msg...) fprintf(stderr, "ERROR: " msg)
67 #define error_ret(ret, msg...) { \
73 static uint16_t crc_x25(uint16_t crc
, void *void_buf
, size_t size
)
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,
83 for (buf
= void_buf
; size
; size
--) {
85 crc
= (crc
<< 4) ^ crc_table
[((crc
>> 12) ^ (data
>> 4)) & 0xf];
86 crc
= (crc
<< 4) ^ crc_table
[((crc
>> 12) ^ (data
>> 0)) & 0xf];
94 static uint16_t crc_16(uint16_t crc
, void *void_buf
, size_t size
)
97 * CRC table for the CRC-16.
98 * The poly is 0x8005 (x^16 + x^15 + x^2 + 1)
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
136 for (buf
= void_buf
; size
; size
--) {
138 crc
= (crc
>> 8) ^ crc16_table
[(crc
^ data
) & 0xff];
145 static const struct crc_t crc_type
= {
151 #elif defined(CRC_X25)
159 static int write_binary(FILE *out
, FILE *in
, struct bimg_header
*hdr
)
161 static uint8_t file_buf
[MAX_RECORD_BYTES
];
162 struct bimg_data_header data_hdr
= { 0 };
165 data_hdr
.dest_addr
= hdr
->entry_addr
;
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.
172 while ((data_hdr
.size
= fread(file_buf
, 1, sizeof(file_buf
), in
))) {
173 data_hdr
.crc
= crc_type
.crc_f(crc_type
.crc_init
, &data_hdr
,
174 sizeof(data_hdr
) - sizeof(data_hdr
.crc
));
176 if (fwrite(&data_hdr
, sizeof(data_hdr
), 1, out
) != 1)
177 error_ret(-EIO
, "Failed to write data header: %d\n",
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",
185 data_hdr
.dest_addr
+= n_written
;
186 hdr
->data_size
+= sizeof(data_hdr
) + n_written
;
187 hdr
->data_crc
= crc_type
.crc_f(hdr
->data_crc
,
188 file_buf
, n_written
);
192 error_ret(-EIO
, "Failed to read input file\n");
197 static int write_final(FILE *out
, struct bimg_header
*hdr
)
199 struct bimg_data_header data_hdr
= {
204 data_hdr
.crc
= crc_type
.crc_f(crc_type
.crc_init
, &data_hdr
,
205 sizeof(data_hdr
) - sizeof(data_hdr
.crc
));
207 if (fwrite(&data_hdr
, sizeof(data_hdr
), 1, out
) != 1)
208 error_ret(-EIO
, "Failed to write data header: %d\n", errno
);
210 hdr
->data_size
+= sizeof(data_hdr
);
215 static const char *help_message
=
216 "Usage: bimgtool <input> [<output> <base-address>]\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"
223 " input: The binary file to be converted to a BIMG\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";
229 static void usage(FILE *f
)
231 fprintf(f
, help_message
, crc_type
.ver_major
);
234 static int verify_file(FILE *f
)
236 struct bimg_header file_header
;
237 struct bimg_data_header data_header
;
243 uint32_t data_crc
= crc_type
.crc_init
;
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");
252 if (fstat(fd
, &buf
)) {
253 perror("Problems trying to stat input file\n");
257 if (file_header
.magic
!= BIMG_MAGIC
) {
258 fprintf(stderr
, "Wrong magic value %#x\n", file_header
.magic
);
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");
270 if ((file_header
.data_size
+ sizeof(struct bimg_header
)) >
272 fprintf(stderr
, "Data size too big: %d > %zd\n",
273 file_header
.data_size
, buf
.st_size
);
277 if (file_header
.ver_major
!= crc_type
.ver_major
) {
278 fprintf(stderr
, "Image version mismatch: %d\n",
279 file_header
.ver_major
);
283 if ((file_header
.flags
& BIMG_FLAGS
) != BIMG_FLAGS
) {
284 fprintf(stderr
, "Unexpected file header flags: %#x\n",
289 if (file_header
.ver_minor
!= crc_type
.ver_minor
) {
291 "Minor version mismatch: %d, will try anyways\n",
292 file_header
.ver_minor
);
295 data_size
= file_header
.data_size
;
296 file_pointer
= malloc(data_size
);
298 fprintf(stderr
, "Failed to allocate %d bytes\n",
299 file_header
.data_size
);
303 if (fread(file_pointer
, 1, data_size
, f
) != data_size
) {
304 fprintf(stderr
, "Failed to read %d bytes\n", data_size
);
309 file_data
= file_pointer
;
310 while (data_size
> 0) {
311 memcpy(&data_header
, file_data
, sizeof(data_header
));
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
);
325 * Add the block data to the CRC stream, the last block size
328 file_data
+= sizeof(data_header
);
329 data_crc
= crc_type
.crc_f(data_crc
,
330 file_data
, data_header
.size
);
332 data_size
-= data_header
.size
+ sizeof(data_header
);
333 file_data
+= data_header
.size
;
337 fprintf(stderr
, "File size mismatch\n");
342 if (data_crc
!= file_header
.data_crc
) {
343 fprintf(stderr
, "File data CRC mismatch\n");
352 int main(int argc
, char *argv
[])
354 const char *in_filename
, *out_filename
;
355 FILE *in_file
, *out_file
;
357 struct bimg_header hdr
= {
359 .ver_major
= crc_type
.ver_major
,
360 .ver_minor
= crc_type
.ver_minor
,
362 .data_crc
= crc_type
.crc_init
,
365 if ((argc
!= 4) && (argc
!= 2)) {
370 in_filename
= argv
[1];
372 in_file
= fopen(in_filename
, "r");
374 error("Failed to open input file '%s'\n", in_filename
);
379 return verify_file(in_file
);
381 out_filename
= argv
[2];
382 hdr
.entry_addr
= strtoul(argv
[3], NULL
, 16);
384 out_file
= fopen(out_filename
, "w");
386 error("Failed to open output file '%s'\n", out_filename
);
387 goto out_err_close_in
;
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
;
395 err
= write_binary(out_file
, in_file
, &hdr
);
397 error("Failed to write binary: %d\n", err
);
398 goto out_err_close_out
;
401 err
= write_final(out_file
, &hdr
);
403 error("Failed to write final record: %d\n", err
);
404 goto out_err_close_out
;
407 hdr
.crc
= crc_type
.crc_f(crc_type
.crc_init
, &hdr
,
408 sizeof(hdr
) - sizeof(hdr
.crc
));
410 if (fseek(out_file
, 0, SEEK_SET
)) {
411 error("Failed to seek to header: %d\n", errno
);
412 goto out_err_close_out
;
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
;