c9d838a2e131c4a66ec0f53101339f6ea6c14490
[openwrt/openwrt.git] / tools / firmware-utils / src / mkfwimage.c
1 /*
2 * Copyright (C) 2007 Ubiquiti Networks, Inc.
3 * Copyright (C) 2008 Lukas Kuna <ValXdater@seznam.cz>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <inttypes.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <zlib.h>
28 #include <sys/mman.h>
29 #include <netinet/in.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <limits.h>
33 #include <stdbool.h>
34 #include "fw.h"
35
36 typedef struct fw_layout_data {
37 u_int32_t kern_start;
38 u_int32_t kern_entry;
39 u_int32_t firmware_max_length;
40 } fw_layout_t;
41
42 struct fw_info {
43 char name[PATH_MAX];
44 struct fw_layout_data fw_layout;
45 bool sign;
46 };
47
48 struct fw_info fw_info[] = {
49 {
50 .name = "XS2",
51 .fw_layout = {
52 .kern_start = 0xbfc30000,
53 .kern_entry = 0x80041000,
54 .firmware_max_length= 0x00390000,
55 },
56 .sign = false,
57 },
58 {
59 .name = "XS5",
60 .fw_layout = {
61 .kern_start = 0xbe030000,
62 .kern_entry = 0x80041000,
63 .firmware_max_length= 0x00390000,
64 },
65 .sign = false,
66 },
67 {
68 .name = "RS",
69 .fw_layout = {
70 .kern_start = 0xbf030000,
71 .kern_entry = 0x80060000,
72 .firmware_max_length= 0x00B00000,
73 },
74 .sign = false,
75 },
76 {
77 .name = "RSPRO",
78 .fw_layout = {
79 .kern_start = 0xbf030000,
80 .kern_entry = 0x80060000,
81 .firmware_max_length= 0x00F00000,
82 },
83 .sign = false,
84 },
85 {
86 .name = "LS-SR71",
87 .fw_layout = {
88 .kern_start = 0xbf030000,
89 .kern_entry = 0x80060000,
90 .firmware_max_length= 0x00640000,
91 },
92 .sign = false,
93 },
94 {
95 .name = "XS2-8",
96 .fw_layout = {
97 .kern_start = 0xa8030000,
98 .kern_entry = 0x80041000,
99 .firmware_max_length= 0x006C0000,
100 },
101 .sign = false,
102
103 },
104 {
105 .name = "XM",
106 .fw_layout = {
107 .kern_start = 0x9f050000,
108 .kern_entry = 0x80002000,
109 .firmware_max_length= 0x00760000,
110 },
111 .sign = false,
112 },
113 {
114 .name = "UBDEV01",
115 .fw_layout = {
116 .kern_start = 0x9f050000,
117 .kern_entry = 0x80002000,
118 .firmware_max_length= 0x006A0000,
119 },
120 .sign = false,
121 },
122 {
123 .name = "WA",
124 .fw_layout = {
125 .kern_start = 0x9f050000,
126 .kern_entry = 0x80002000,
127 .firmware_max_length= 0x00F60000,
128 },
129 .sign = true,
130 },
131 {
132 .name = "ACB-ISP",
133 .fw_layout = {
134 .kern_start = 0x9f050000,
135 .kern_entry = 0x80002000,
136 .firmware_max_length= 0x00F60000,
137 },
138 .sign = true,
139 },
140 {
141 .name = "",
142 },
143 };
144
145 typedef struct part_data {
146 char partition_name[64];
147 int partition_index;
148 u_int32_t partition_baseaddr;
149 u_int32_t partition_startaddr;
150 u_int32_t partition_memaddr;
151 u_int32_t partition_entryaddr;
152 u_int32_t partition_length;
153
154 char filename[PATH_MAX];
155 struct stat stats;
156 } part_data_t;
157
158 #define MAX_SECTIONS 8
159 #define DEFAULT_OUTPUT_FILE "firmware-image.bin"
160 #define DEFAULT_VERSION "UNKNOWN"
161
162 #define OPTIONS "B:hv:m:o:r:k:"
163
164 typedef struct image_info {
165 char magic[16];
166 char version[256];
167 char outputfile[PATH_MAX];
168 u_int32_t part_count;
169 part_data_t parts[MAX_SECTIONS];
170 struct fw_info* fwinfo;
171 } image_info_t;
172
173 static struct fw_info* get_fwinfo(char* board_name) {
174 struct fw_info *fwinfo = fw_info;
175 while(strlen(fwinfo->name)) {
176 if(strcmp(fwinfo->name, board_name) == 0) {
177 return fwinfo;
178 }
179 fwinfo++;
180 }
181 return NULL;
182 }
183
184 static void write_header(void* mem, const char *magic, const char* version)
185 {
186 header_t* header = mem;
187 memset(header, 0, sizeof(header_t));
188
189 memcpy(header->magic, magic, MAGIC_LENGTH);
190 strncpy(header->version, version, sizeof(header->version));
191 header->crc = htonl(crc32(0L, (unsigned char *)header,
192 sizeof(header_t) - 2 * sizeof(u_int32_t)));
193 header->pad = 0L;
194 }
195
196
197 static void write_signature(void* mem, u_int32_t sig_offset)
198 {
199 /* write signature */
200 signature_t* sign = (signature_t*)(mem + sig_offset);
201 memset(sign, 0, sizeof(signature_t));
202
203 memcpy(sign->magic, MAGIC_END, MAGIC_LENGTH);
204 sign->crc = htonl(crc32(0L,(unsigned char *)mem, sig_offset));
205 sign->pad = 0L;
206 }
207
208 static void write_signature_rsa(void* mem, u_int32_t sig_offset)
209 {
210 /* write signature */
211 signature_rsa_t* sign = (signature_rsa_t*)(mem + sig_offset);
212 memset(sign, 0, sizeof(signature_rsa_t));
213
214 memcpy(sign->magic, MAGIC_ENDS, MAGIC_LENGTH);
215 // sign->crc = htonl(crc32(0L,(unsigned char *)mem, sig_offset));
216 sign->pad = 0L;
217 }
218
219 static int write_part(void* mem, part_data_t* d)
220 {
221 char* addr;
222 int fd;
223 part_t* p = mem;
224 part_crc_t* crc = mem + sizeof(part_t) + d->stats.st_size;
225
226 fd = open(d->filename, O_RDONLY);
227 if (fd < 0)
228 {
229 ERROR("Failed opening file '%s'\n", d->filename);
230 return -1;
231 }
232
233 if ((addr=(char*)mmap(0, d->stats.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED)
234 {
235 ERROR("Failed mmaping memory for file '%s'\n", d->filename);
236 close(fd);
237 return -2;
238 }
239
240 memcpy(mem + sizeof(part_t), addr, d->stats.st_size);
241 munmap(addr, d->stats.st_size);
242
243 memset(p->name, 0, PART_NAME_LENGTH);
244 memcpy(p->magic, MAGIC_PART, MAGIC_LENGTH);
245 memcpy(p->name, d->partition_name, PART_NAME_LENGTH);
246
247 p->index = htonl(d->partition_index);
248 p->data_size = htonl(d->stats.st_size);
249 p->part_size = htonl(d->partition_length);
250 p->baseaddr = htonl(d->partition_baseaddr);
251 p->memaddr = htonl(d->partition_memaddr);
252 p->entryaddr = htonl(d->partition_entryaddr);
253
254 crc->crc = htonl(crc32(0L, mem, d->stats.st_size + sizeof(part_t)));
255 crc->pad = 0L;
256
257 return 0;
258 }
259
260 static void usage(const char* progname)
261 {
262 INFO("Version %s\n"
263 "Usage: %s [options]\n"
264 "\t-v <version string>\t - firmware version information, default: %s\n"
265 "\t-o <output file>\t - firmware output file, default: %s\n"
266 "\t-m <magic>\t - firmware magic, default: %s\n"
267 "\t-k <kernel file>\t\t - kernel file\n"
268 "\t-r <rootfs file>\t\t - rootfs file\n"
269 "\t-B <board name>\t\t - choose firmware layout for specified board (XS2, XS5, RS, XM)\n"
270 "\t-h\t\t\t - this help\n", VERSION,
271 progname, DEFAULT_VERSION, DEFAULT_OUTPUT_FILE, MAGIC_HEADER);
272 }
273
274 static void print_image_info(const image_info_t* im)
275 {
276 unsigned int i = 0;
277
278 INFO("Firmware version: '%s'\n"
279 "Output file: '%s'\n"
280 "Part count: %u\n",
281 im->version, im->outputfile,
282 im->part_count);
283
284 for (i = 0; i < im->part_count; ++i)
285 {
286 const part_data_t* d = &im->parts[i];
287 INFO(" %10s: %8" PRId64 " bytes (free: %8" PRId64 ")\n",
288 d->partition_name,
289 d->stats.st_size,
290 d->partition_length - d->stats.st_size);
291 }
292 }
293
294 static u_int32_t filelength(const char* file)
295 {
296 FILE *p;
297 int ret = -1;
298
299 if ( (p = fopen(file, "rb") ) == NULL) return (-1);
300
301 fseek(p, 0, SEEK_END);
302 ret = ftell(p);
303
304 fclose (p);
305
306 return (ret);
307 }
308
309 static int create_image_layout(const char* kernelfile, const char* rootfsfile, image_info_t* im)
310 {
311 uint32_t rootfs_len = 0;
312 part_data_t* kernel = &im->parts[0];
313 part_data_t* rootfs = &im->parts[1];
314
315 fw_layout_t* p = &im->fwinfo->fw_layout;
316
317 printf("board = %s\n", im->fwinfo->name);
318 strcpy(kernel->partition_name, "kernel");
319 kernel->partition_index = 1;
320 kernel->partition_baseaddr = p->kern_start;
321 if ( (kernel->partition_length = filelength(kernelfile)) == (u_int32_t)-1) return (-1);
322 kernel->partition_memaddr = p->kern_entry;
323 kernel->partition_entryaddr = p->kern_entry;
324 strncpy(kernel->filename, kernelfile, sizeof(kernel->filename));
325
326 rootfs_len = filelength(rootfsfile);
327 if (rootfs_len + kernel->partition_length > p->firmware_max_length) {
328 ERROR("File '%s' too big (0x%08X) - max size: 0x%08X (exceeds %u bytes)\n",
329 rootfsfile, rootfs_len, p->firmware_max_length,
330 (rootfs_len + kernel->partition_length) - p->firmware_max_length);
331 return (-2);
332 }
333
334 strcpy(rootfs->partition_name, "rootfs");
335 rootfs->partition_index = 2;
336 rootfs->partition_baseaddr = kernel->partition_baseaddr + kernel->partition_length;
337 rootfs->partition_length = p->firmware_max_length - kernel->partition_length;
338 rootfs->partition_memaddr = 0x00000000;
339 rootfs->partition_entryaddr = 0x00000000;
340 strncpy(rootfs->filename, rootfsfile, sizeof(rootfs->filename));
341
342 printf("kernel: %d 0x%08x\n", kernel->partition_length, kernel->partition_baseaddr);
343 printf("root: %d 0x%08x\n", rootfs->partition_length, rootfs->partition_baseaddr);
344 im->part_count = 2;
345
346 return 0;
347 }
348
349 /**
350 * Checks the availability and validity of all image components.
351 * Fills in stats member of the part_data structure.
352 */
353 static int validate_image_layout(image_info_t* im)
354 {
355 unsigned int i;
356
357 if (im->part_count == 0 || im->part_count > MAX_SECTIONS)
358 {
359 ERROR("Invalid part count '%d'\n", im->part_count);
360 return -1;
361 }
362
363 for (i = 0; i < im->part_count; ++i)
364 {
365 part_data_t* d = &im->parts[i];
366 int len = strlen(d->partition_name);
367 if (len == 0 || len > 16)
368 {
369 ERROR("Invalid partition name '%s' of the part %d\n",
370 d->partition_name, i);
371 return -1;
372 }
373 if (stat(d->filename, &d->stats) < 0)
374 {
375 ERROR("Couldn't stat file '%s' from part '%s'\n",
376 d->filename, d->partition_name);
377 return -2;
378 }
379 if (d->stats.st_size == 0)
380 {
381 ERROR("File '%s' from part '%s' is empty!\n",
382 d->filename, d->partition_name);
383 return -3;
384 }
385 if (d->stats.st_size > d->partition_length) {
386 ERROR("File '%s' too big (%d) - max size: 0x%08X (exceeds %" PRId64 " bytes)\n",
387 d->filename, i, d->partition_length,
388 d->stats.st_size - d->partition_length);
389 return -4;
390 }
391 }
392
393 return 0;
394 }
395
396 static int build_image(image_info_t* im)
397 {
398 char* mem;
399 char* ptr;
400 u_int32_t mem_size;
401 FILE* f;
402 unsigned int i;
403
404 // build in-memory buffer
405 mem_size = sizeof(header_t);
406 if(im->fwinfo->sign) {
407 mem_size += sizeof(signature_rsa_t);
408 } else {
409 mem_size += sizeof(signature_t);
410 }
411 for (i = 0; i < im->part_count; ++i)
412 {
413 part_data_t* d = &im->parts[i];
414 mem_size += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
415 }
416
417 mem = (char*)calloc(mem_size, 1);
418 if (mem == NULL)
419 {
420 ERROR("Cannot allocate memory chunk of size '%u'\n", mem_size);
421 return -1;
422 }
423
424 // write header
425 write_header(mem, im->magic, im->version);
426 ptr = mem + sizeof(header_t);
427 // write all parts
428 for (i = 0; i < im->part_count; ++i)
429 {
430 part_data_t* d = &im->parts[i];
431 int rc;
432 if ((rc = write_part(ptr, d)) != 0)
433 {
434 ERROR("ERROR: failed writing part %u '%s'\n", i, d->partition_name);
435 }
436 ptr += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
437 }
438 // write signature
439 if(im->fwinfo->sign) {
440 write_signature_rsa(mem, mem_size - sizeof(signature_rsa_t));
441 } else {
442 write_signature(mem, mem_size - sizeof(signature_t));
443 }
444
445 // write in-memory buffer into file
446 if ((f = fopen(im->outputfile, "w")) == NULL)
447 {
448 ERROR("Can not create output file: '%s'\n", im->outputfile);
449 return -10;
450 }
451
452 if (fwrite(mem, mem_size, 1, f) != 1)
453 {
454 ERROR("Could not write %d bytes into file: '%s'\n",
455 mem_size, im->outputfile);
456 return -11;
457 }
458
459 free(mem);
460 fclose(f);
461 return 0;
462 }
463
464
465 int main(int argc, char* argv[])
466 {
467 char kernelfile[PATH_MAX];
468 char rootfsfile[PATH_MAX];
469 char board_name[PATH_MAX];
470 int o, rc;
471 image_info_t im;
472 struct fw_info *fwinfo;
473
474 memset(&im, 0, sizeof(im));
475 memset(kernelfile, 0, sizeof(kernelfile));
476 memset(rootfsfile, 0, sizeof(rootfsfile));
477 memset(board_name, 0, sizeof(board_name));
478
479 strcpy(im.outputfile, DEFAULT_OUTPUT_FILE);
480 strcpy(im.version, DEFAULT_VERSION);
481 strncpy(im.magic, MAGIC_HEADER, sizeof(im.magic));
482
483 while ((o = getopt(argc, argv, OPTIONS)) != -1)
484 {
485 switch (o) {
486 case 'v':
487 if (optarg)
488 strncpy(im.version, optarg, sizeof(im.version) - 1);
489 break;
490 case 'o':
491 if (optarg)
492 strncpy(im.outputfile, optarg, sizeof(im.outputfile) - 1);
493 break;
494 case 'm':
495 if (optarg)
496 strncpy(im.magic, optarg, sizeof(im.magic) - 1);
497 break;
498 case 'h':
499 usage(argv[0]);
500 return -1;
501 case 'k':
502 if (optarg)
503 strncpy(kernelfile, optarg, sizeof(kernelfile) - 1);
504 break;
505 case 'r':
506 if (optarg)
507 strncpy(rootfsfile, optarg, sizeof(rootfsfile) - 1);
508 break;
509 case 'B':
510 if (optarg)
511 strncpy(board_name, optarg, sizeof(board_name) - 1);
512 break;
513 }
514 }
515 if (strlen(board_name) == 0)
516 strcpy(board_name, "XS2"); /* default to XS2 */
517
518 if (strlen(kernelfile) == 0)
519 {
520 ERROR("Kernel file is not specified, cannot continue\n");
521 usage(argv[0]);
522 return -2;
523 }
524
525 if (strlen(rootfsfile) == 0)
526 {
527 ERROR("Root FS file is not specified, cannot continue\n");
528 usage(argv[0]);
529 return -2;
530 }
531
532 if ((fwinfo = get_fwinfo(board_name)) == NULL) {
533 ERROR("Invalid baord name '%s'\n", board_name);
534 usage(argv[0]);
535 return -2;
536 }
537
538 im.fwinfo = fwinfo;
539
540 if ((rc = create_image_layout(kernelfile, rootfsfile, &im)) != 0)
541 {
542 ERROR("Failed creating firmware layout description - error code: %d\n", rc);
543 return -3;
544 }
545
546 if ((rc = validate_image_layout(&im)) != 0)
547 {
548 ERROR("Failed validating firmware layout - error code: %d\n", rc);
549 return -4;
550 }
551
552 print_image_info(&im);
553
554 if ((rc = build_image(&im)) != 0)
555 {
556 ERROR("Failed building image file '%s' - error code: %d\n", im.outputfile, rc);
557 return -5;
558 }
559
560 return 0;
561 }