• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/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 }
570 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt