mb: Set coreboot as DSDT's manufacturer model ID
[coreboot.git] / util / bimgtool / bimgtool.c
blob518674cf64a5d302ef9dbb8814a55e34e4187533
1 /*
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
9 * the License.
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.
17 #include <errno.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
25 struct 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));
36 struct bimg_data_header {
37 uint32_t size;
38 uint32_t dest_addr;
39 uint16_t dummy;
40 uint16_t crc;
41 } __attribute__((packed));
43 struct 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;
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
63 #define CRC_16
65 #define error(msg...) fprintf(stderr, "ERROR: " msg)
67 #define error_ret(ret, msg...) { \
68 error(msg); \
69 return ret; \
72 #if defined(CRC_X25)
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,
81 uint8_t *buf, data;
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];
89 return crc;
91 #endif
93 #if defined(CRC_16)
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
134 uint8_t *buf, data;
136 for (buf = void_buf; size; size--) {
137 data = *buf++;
138 crc = (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
141 return crc;
143 #endif
145 static const struct crc_t crc_type = {
146 #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
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 };
163 size_t n_written;
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",
178 errno);
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);
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);
191 if (ferror(in))
192 error_ret(-EIO, "Failed to read input file\n");
194 return 0;
197 static int write_final(FILE *out, struct bimg_header *hdr)
199 struct bimg_data_header data_hdr = {
200 .size = 0,
201 .dest_addr = ~0,
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);
212 return 0;
215 static 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";
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;
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;
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;
252 if (fstat(fd, &buf)) {
253 perror("Problems trying to stat input file\n");
254 return -1;
257 if (file_header.magic != BIMG_MAGIC) {
258 fprintf(stderr, "Wrong magic value %#x\n", file_header.magic);
259 return -1;
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;
270 if ((file_header.data_size + sizeof(struct bimg_header)) >
271 buf.st_size) {
272 fprintf(stderr, "Data size too big: %d > %zd\n",
273 file_header.data_size, buf.st_size);
274 return -1;
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;
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;
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);
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;
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;
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);
320 free(file_pointer);
321 return -1;
325 * Add the block data to the CRC stream, the last block size
326 * will be zero.
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;
336 if (data_size) {
337 fprintf(stderr, "File size mismatch\n");
338 free(file_pointer);
339 return -1;
342 if (data_crc != file_header.data_crc) {
343 fprintf(stderr, "File data CRC mismatch\n");
344 free(file_pointer);
345 return -1;
348 free(file_pointer);
349 return 0;
352 int main(int argc, char *argv[])
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,
359 .ver_major = crc_type.ver_major,
360 .ver_minor = crc_type.ver_minor,
361 .flags = BIMG_FLAGS,
362 .data_crc = crc_type.crc_init,
365 if ((argc != 4) && (argc != 2)) {
366 usage(stderr);
367 goto out_err;
370 in_filename = argv[1];
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;
378 if (argc == 2)
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");
385 if (!out_file) {
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);
396 if (err) {
397 error("Failed to write binary: %d\n", err);
398 goto out_err_close_out;
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;
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;
420 fclose(in_file);
421 fclose(out_file);
422 return EXIT_SUCCESS;
424 out_err_close_out:
425 fclose(out_file);
426 out_err_close_in:
427 fclose(in_file);
428 out_err:
429 return EXIT_FAILURE;