Advertisement
Twissel

ubnt-mkfwimage

Mar 9th, 2015
450
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.44 KB | None | 0 0
  1. /*
  2.  * Copyright (C) 2007 Ubiquiti Networks, Inc.
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License as
  6.  * published by the Free Software Foundation; either version 2 of the
  7.  * License, or (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful, but
  10.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.  * General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */
  18.  
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <fcntl.h>
  22. #include <unistd.h>
  23. #include <string.h>
  24. #include <errno.h>
  25. #include <zlib.h>
  26. #include <sys/mman.h>
  27. #include <netinet/in.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <limits.h>
  31.  
  32. #include "fw.h"
  33.  
  34. typedef struct part_data {
  35.     char    partition_name[64];
  36.     int     partition_index;
  37.     u_int32_t   partition_baseaddr;
  38.     u_int32_t   partition_memaddr;
  39.     u_int32_t   partition_entryaddr;
  40.     u_int32_t  partition_length;
  41.  
  42.     char    filename[PATH_MAX];
  43.     struct stat stats;
  44. } part_data_t;
  45.  
  46. #define MAX_SECTIONS    4
  47. #define DEFAULT_OUTPUT_FILE     "firmware-image.bin"
  48. #define DEFAULT_VERSION     "UNKNOWN"
  49.  
  50. #define OPTIONS "hv:o:i:"
  51.  
  52. static int debug = 0;
  53.  
  54. typedef struct image_info {
  55.     char version[256];
  56.     char outputfile[PATH_MAX];
  57.     u_int32_t   part_count;
  58.     part_data_t parts[MAX_SECTIONS];
  59. } image_info_t;
  60.  
  61. static void write_header(void* mem, const char* version)
  62. {
  63.     header_t* header = mem;
  64.     memset(header, 0, sizeof(header_t));
  65.  
  66.     memcpy(header->magic, MAGIC_HEADER, MAGIC_LENGTH);
  67.     strncpy(header->version, version, sizeof(header->version));
  68.     header->crc = htonl(crc32(0L, (unsigned char *)header,
  69.                 sizeof(header_t) - 2 * sizeof(u_int32_t)));
  70.     header->pad = 0L;
  71. }
  72.  
  73.  
  74. static void write_signature(void* mem, u_int32_t sig_offset)
  75. {
  76.     /* write signature */
  77.     signature_t* sign = (signature_t*)(mem + sig_offset);
  78.     memset(sign, 0, sizeof(signature_t));
  79.  
  80.     memcpy(sign->magic, MAGIC_END, MAGIC_LENGTH);
  81.     sign->crc = htonl(crc32(0L,(unsigned char *)mem, sig_offset));
  82.     sign->pad = 0L;
  83. }
  84.  
  85. static int write_part(void* mem, part_data_t* d)
  86. {
  87.     char* addr;
  88.     int fd;
  89.     part_t* p = mem;
  90.     part_crc_t* crc = mem + sizeof(part_t) + d->stats.st_size;
  91.  
  92.     fd = open(d->filename, O_RDONLY);
  93.     if (fd < 0)
  94.     {
  95.         ERROR("Failed opening file '%s'\n", d->filename);
  96.         return -1;
  97.     }
  98.  
  99.     if ((addr=(char*)mmap(0, d->stats.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED)
  100.     {
  101.         ERROR("Failed mmaping memory for file '%s'\n", d->filename);
  102.         close(fd);
  103.         return -2;
  104.     }
  105.  
  106.     memcpy(mem + sizeof(part_t), addr, d->stats.st_size);
  107.     munmap(addr, d->stats.st_size);
  108.  
  109.     memset(p->name, 0, sizeof(p->name));
  110.     strncpy(p->magic, MAGIC_PART, MAGIC_LENGTH);
  111.     strncpy(p->name, d->partition_name, sizeof(p->name));
  112.     p->index = htonl(d->partition_index);
  113.     p->data_size = htonl(d->stats.st_size);
  114.     p->part_size = htonl(d->partition_length);
  115.     p->baseaddr = htonl(d->partition_baseaddr);
  116.     p->memaddr = htonl(d->partition_memaddr);
  117.     p->entryaddr = htonl(d->partition_entryaddr);
  118.  
  119.     crc->crc = htonl(crc32(0L, mem, d->stats.st_size + sizeof(part_t)));
  120.     crc->pad = 0L;
  121.  
  122.     return 0;
  123. }
  124.  
  125. static void usage(const char* progname)
  126. {
  127.     INFO("Version %s\n"
  128.              "Usage: %s [options]\n"
  129.          "\t-v <version string>\t - firmware version information, default: %s\n"
  130.          "\t-o <output file>\t - firmware output file, default: %s\n"
  131.          "\t-i <input file>\t\t - firmware layout file, default: none\n"
  132.          "\t-h\t\t\t - this help\n", VERSION,
  133.          progname, DEFAULT_VERSION, DEFAULT_OUTPUT_FILE);
  134. }
  135.  
  136. static void print_image_info(const image_info_t* im)
  137. {
  138.     int i = 0;
  139.     INFO("Firmware version: '%s'\n"
  140.          "Output file: '%s'\n"
  141.          "Part count: %u\n",
  142.          im->version, im->outputfile,
  143.          im->part_count);
  144.  
  145.     for (i = 0; i < im->part_count; ++i)
  146.     {
  147.         const part_data_t* d = &im->parts[i];
  148.         INFO(" %10s: %8ld bytes (free: %8ld)\n",
  149.              d->partition_name,
  150.              d->stats.st_size,
  151.              d->partition_length - d->stats.st_size);
  152.     }
  153. }
  154.  
  155.  
  156.  
  157. /**
  158.  * Image layout file format:
  159.  *
  160.  * <partition name>\t<partition index>\t<partition size>\t<data file name>
  161.  *
  162.  */
  163. static int parse_image_layout(const char* layoutfile, image_info_t* im)
  164. {
  165.     int fd = 0;
  166.     char line[1028];
  167.     FILE* f;
  168.  
  169.     im->part_count = 0;
  170.  
  171.     fd = open(layoutfile, O_RDONLY);
  172.     if (fd < 0) {
  173.         ERROR("Could not open file '%s'\n", layoutfile);
  174.         return -1;
  175.     }
  176.  
  177.     f = fdopen(fd, "r");
  178.     if (f == NULL) {
  179.         close(fd);
  180.         return -2;
  181.     }
  182.  
  183.     while (!feof(f))
  184.     {
  185.         char name[32];
  186.         u_int32_t index;
  187.         u_int32_t baseaddr;
  188.         u_int32_t size;
  189.         u_int32_t memaddr;
  190.         u_int32_t entryaddr;
  191.         char file[PATH_MAX];
  192.         u_int32_t c;
  193.         part_data_t* d;
  194.  
  195.         if (fgets(line, sizeof(line), f) == NULL)
  196.             break;
  197.  
  198.         // TODO: very inconvenient format, use smarter parsing someday
  199.         if ((c = sscanf(line, "%32[^\t]\t%X\t%X\t%X\t%X\t%X\t%128[^\t\n]", name, &index, &baseaddr, &size, &memaddr, &entryaddr, file)) != 7)
  200.                 continue;
  201.  
  202.         DEBUG("%s\t\t0x%02X\t0x%08X\t0x%08X\t0x%08X\t0x%08X\t%s\n", name, index, baseaddr, size, memaddr, entryaddr, file);
  203.  
  204.         c = im->part_count;
  205.         if (c == MAX_SECTIONS)
  206.             break;
  207.  
  208.         d = &im->parts[c];
  209.         strncpy(d->partition_name, name, sizeof(d->partition_name));
  210.         d->partition_index = index;
  211.         d->partition_baseaddr = baseaddr;
  212.         d->partition_length = size;
  213.         d->partition_memaddr = memaddr;
  214.         d->partition_entryaddr = entryaddr;
  215.         strncpy(d->filename, file, sizeof(d->filename));
  216.  
  217.         im->part_count++;
  218.     }
  219.  
  220.     fclose(f);
  221.  
  222.     return 0;
  223. }
  224.  
  225. /**
  226.  * Checks the availability and validity of all image components.
  227.  * Fills in stats member of the part_data structure.
  228.  */
  229. static int validate_image_layout(image_info_t* im)
  230. {
  231.     int i;
  232.  
  233.     if (im->part_count == 0 || im->part_count > MAX_SECTIONS)
  234.     {
  235.         ERROR("Invalid part count '%d'\n", im->part_count);
  236.         return -1;
  237.     }
  238.  
  239.     for (i = 0; i < im->part_count; ++i)
  240.     {
  241.         part_data_t* d = &im->parts[i];
  242.         int len = strlen(d->partition_name);
  243.         if (len == 0 || len > 16)
  244.         {
  245.             ERROR("Invalid partition name '%s' of the part %d\n",
  246.                     d->partition_name, i);
  247.             return -1;
  248.         }
  249.         if (stat(d->filename, &d->stats) < 0)
  250.         {
  251.             ERROR("Couldn't stat file '%s' from part '%s'\n",
  252.                         d->filename, d->partition_name);
  253.             return -2;
  254.         }
  255.         if (d->stats.st_size == 0)
  256.         {
  257.             ERROR("File '%s' from part '%s' is empty!\n",
  258.                         d->filename, d->partition_name);
  259.             return -3;
  260.         }
  261.         if (d->stats.st_size > d->partition_length) {
  262.             ERROR("File '%s' too big (%d) - max size: 0x%08X (exceeds %lu bytes)\n",
  263.                         d->filename, i, d->partition_length,
  264.                     d->stats.st_size - d->partition_length);
  265.             return -4;
  266.         }
  267.     }
  268.  
  269.     return 0;
  270. }
  271.  
  272. static int build_image(image_info_t* im)
  273. {
  274.     char* mem;
  275.     char* ptr;
  276.     u_int32_t mem_size;
  277.     FILE* f;
  278.     int i;
  279.  
  280.     // build in-memory buffer
  281.     mem_size = sizeof(header_t) + sizeof(signature_t);
  282.     for (i = 0; i < im->part_count; ++i)
  283.     {
  284.         part_data_t* d = &im->parts[i];
  285.         mem_size += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
  286.     }
  287.  
  288.     mem = (char*)calloc(mem_size, 1);
  289.     if (mem == NULL)
  290.     {
  291.         ERROR("Cannot allocate memory chunk of size '%u'\n", mem_size);
  292.         return -1;
  293.     }
  294.  
  295.     // write header
  296.     write_header(mem, im->version);
  297.     ptr = mem + sizeof(header_t);
  298.     // write all parts
  299.     for (i = 0; i < im->part_count; ++i)
  300.     {
  301.         part_data_t* d = &im->parts[i];
  302.         int rc;
  303.         if ((rc = write_part(ptr, d)) != 0)
  304.         {
  305.             ERROR("ERROR: failed writing part %u '%s'\n", i, d->partition_name);
  306.         }
  307.         ptr += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
  308.     }
  309.     // write signature
  310.     write_signature(mem, mem_size - sizeof(signature_t));
  311.  
  312.     // write in-memory buffer into file
  313.     if ((f = fopen(im->outputfile, "w")) == NULL)
  314.     {
  315.         ERROR("Can not create output file: '%s'\n", im->outputfile);
  316.         return -10;
  317.     }
  318.  
  319.     if (fwrite(mem, mem_size, 1, f) != 1)
  320.     {
  321.         ERROR("Could not write %d bytes into file: '%s'\n",
  322.                 mem_size, im->outputfile);
  323.         return -11;
  324.     }
  325.  
  326.     free(mem);
  327.     fclose(f);
  328.     return 0;
  329. }
  330.  
  331.  
  332. int main(int argc, char* argv[])
  333. {
  334.     char inputfile[PATH_MAX];
  335.     int o, rc;
  336.     image_info_t im;
  337.  
  338.     memset(&im, 0, sizeof(im));
  339.     memset(inputfile, 0, sizeof(inputfile));
  340.  
  341.     strcpy(im.outputfile, DEFAULT_OUTPUT_FILE);
  342.     strcpy(im.version, DEFAULT_VERSION);
  343.  
  344.     while ((o = getopt(argc, argv, OPTIONS)) != -1)
  345.     {
  346.         switch (o) {
  347.         case 'v':
  348.             if (optarg)
  349.                 strncpy(im.version, optarg, sizeof(im.version));
  350.             break;
  351.         case 'o':
  352.             if (optarg)
  353.                 strncpy(im.outputfile, optarg, sizeof(im.outputfile));
  354.             break;
  355.         case 'i':
  356.             if (optarg)
  357.                 strncpy(inputfile, optarg, sizeof(inputfile));
  358.             break;
  359.         case 'h':
  360.             usage(argv[0]);
  361.             return -1;
  362.         }
  363.     }
  364.  
  365.     if (strlen(inputfile) == 0)
  366.     {
  367.         ERROR("Input file is not specified, cannot continue\n");
  368.         usage(argv[0]);
  369.         return -2;
  370.     }
  371.  
  372.     if ((rc = parse_image_layout(inputfile, &im)) != 0)
  373.     {
  374.         ERROR("Failed parsing firmware layout file '%s' - error code: %d\n",
  375.             inputfile, rc);
  376.         return -3;
  377.     }
  378.  
  379.     if ((rc = validate_image_layout(&im)) != 0)
  380.     {
  381.         ERROR("Failed validating firmware layout - error code: %d\n", rc);
  382.         return -4;
  383.     }
  384.  
  385.     print_image_info(&im);
  386.  
  387.     if ((rc = build_image(&im)) != 0)
  388.     {
  389.         ERROR("Failed building image file '%s' - error code: %d\n", im.outputfile, rc);
  390.         return -5;
  391.     }
  392.  
  393.     return 0;
  394. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement