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