The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/firmware/ihex2fw.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Parser/loader for IHEX formatted data.
    3  *
    4  * Copyright © 2008 David Woodhouse <dwmw2@infradead.org>
    5  * Copyright © 2005 Jan Harkes <jaharkes@cs.cmu.edu>
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License version 2 as
    9  * published by the Free Software Foundation.
   10  */
   11 
   12 #include <stdint.h>
   13 #include <arpa/inet.h>
   14 #include <stdio.h>
   15 #include <errno.h>
   16 #include <sys/types.h>
   17 #include <sys/stat.h>
   18 #include <sys/mman.h>
   19 #include <fcntl.h>
   20 #include <string.h>
   21 #include <unistd.h>
   22 #include <stdlib.h>
   23 #define _GNU_SOURCE
   24 #include <getopt.h>
   25 
   26 
   27 struct ihex_binrec {
   28         struct ihex_binrec *next; /* not part of the real data structure */
   29         uint32_t addr;
   30         uint16_t len;
   31         uint8_t data[];
   32 };
   33 
   34 /**
   35  * nybble/hex are little helpers to parse hexadecimal numbers to a byte value
   36  **/
   37 static uint8_t nybble(const uint8_t n)
   38 {
   39        if      (n >= '' && n <= '9') return n - '';
   40        else if (n >= 'A' && n <= 'F') return n - ('A' - 10);
   41        else if (n >= 'a' && n <= 'f') return n - ('a' - 10);
   42        return 0;
   43 }
   44 
   45 static uint8_t hex(const uint8_t *data, uint8_t *crc)
   46 {
   47        uint8_t val = (nybble(data[0]) << 4) | nybble(data[1]);
   48        *crc += val;
   49        return val;
   50 }
   51 
   52 static int process_ihex(uint8_t *data, ssize_t size);
   53 static void file_record(struct ihex_binrec *record);
   54 static int output_records(int outfd);
   55 
   56 static int sort_records = 0;
   57 static int wide_records = 0;
   58 static int include_jump = 0;
   59 
   60 static int usage(void)
   61 {
   62         fprintf(stderr, "ihex2fw: Convert ihex files into binary "
   63                 "representation for use by Linux kernel\n");
   64         fprintf(stderr, "usage: ihex2fw [<options>] <src.HEX> <dst.fw>\n");
   65         fprintf(stderr, "       -w: wide records (16-bit length)\n");
   66         fprintf(stderr, "       -s: sort records by address\n");
   67         fprintf(stderr, "       -j: include records for CS:IP/EIP address\n");
   68         return 1;
   69 }
   70 
   71 int main(int argc, char **argv)
   72 {
   73         int infd, outfd;
   74         struct stat st;
   75         uint8_t *data;
   76         int opt;
   77 
   78         while ((opt = getopt(argc, argv, "wsj")) != -1) {
   79                 switch (opt) {
   80                 case 'w':
   81                         wide_records = 1;
   82                         break;
   83                 case 's':
   84                         sort_records = 1;
   85                         break;
   86                 case 'j':
   87                         include_jump = 1;
   88                         break;
   89                         return usage();
   90                 }
   91         }
   92 
   93         if (optind + 2 != argc)
   94                 return usage();
   95 
   96         if (!strcmp(argv[optind], "-"))
   97             infd = 0;
   98         else
   99                 infd = open(argv[optind], O_RDONLY);
  100         if (infd == -1) {
  101                 fprintf(stderr, "Failed to open source file: %s",
  102                         strerror(errno));
  103                 return usage();
  104         }
  105         if (fstat(infd, &st)) {
  106                 perror("stat");
  107                 return 1;
  108         }
  109         data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, infd, 0);
  110         if (data == MAP_FAILED) {
  111                 perror("mmap");
  112                 return 1;
  113         }
  114 
  115         if (!strcmp(argv[optind+1], "-"))
  116             outfd = 1;
  117         else
  118                 outfd = open(argv[optind+1], O_TRUNC|O_CREAT|O_WRONLY, 0644);
  119         if (outfd == -1) {
  120                 fprintf(stderr, "Failed to open destination file: %s",
  121                         strerror(errno));
  122                 return usage();
  123         }
  124         if (process_ihex(data, st.st_size))
  125                 return 1;
  126 
  127         return output_records(outfd);
  128 }
  129 
  130 static int process_ihex(uint8_t *data, ssize_t size)
  131 {
  132         struct ihex_binrec *record;
  133         uint32_t offset = 0;
  134         uint32_t data32;
  135         uint8_t type, crc = 0, crcbyte = 0;
  136         int i, j;
  137         int line = 1;
  138         int len;
  139 
  140         i = 0;
  141 next_record:
  142         /* search for the start of record character */
  143         while (i < size) {
  144                 if (data[i] == '\n') line++;
  145                 if (data[i++] == ':') break;
  146         }
  147 
  148         /* Minimum record length would be about 10 characters */
  149         if (i + 10 > size) {
  150                 fprintf(stderr, "Can't find valid record at line %d\n", line);
  151                 return -EINVAL;
  152         }
  153 
  154         len = hex(data + i, &crc); i += 2;
  155         if (wide_records) {
  156                 len <<= 8;
  157                 len += hex(data + i, &crc); i += 2;
  158         }
  159         record = malloc((sizeof (*record) + len + 3) & ~3);
  160         if (!record) {
  161                 fprintf(stderr, "out of memory for records\n");
  162                 return -ENOMEM;
  163         }
  164         memset(record, 0, (sizeof(*record) + len + 3) & ~3);
  165         record->len = len;
  166 
  167         /* now check if we have enough data to read everything */
  168         if (i + 8 + (record->len * 2) > size) {
  169                 fprintf(stderr, "Not enough data to read complete record at line %d\n",
  170                         line);
  171                 return -EINVAL;
  172         }
  173 
  174         record->addr  = hex(data + i, &crc) << 8; i += 2;
  175         record->addr |= hex(data + i, &crc); i += 2;
  176         type = hex(data + i, &crc); i += 2;
  177 
  178         for (j = 0; j < record->len; j++, i += 2)
  179                 record->data[j] = hex(data + i, &crc);
  180 
  181         /* check CRC */
  182         crcbyte = hex(data + i, &crc); i += 2;
  183         if (crc != 0) {
  184                 fprintf(stderr, "CRC failure at line %d: got 0x%X, expected 0x%X\n",
  185                         line, crcbyte, (unsigned char)(crcbyte-crc));
  186                 return -EINVAL;
  187         }
  188 
  189         /* Done reading the record */
  190         switch (type) {
  191         case 0:
  192                 /* old style EOF record? */
  193                 if (!record->len)
  194                         break;
  195 
  196                 record->addr += offset;
  197                 file_record(record);
  198                 goto next_record;
  199 
  200         case 1: /* End-Of-File Record */
  201                 if (record->addr || record->len) {
  202                         fprintf(stderr, "Bad EOF record (type 01) format at line %d",
  203                                 line);
  204                         return -EINVAL;
  205                 }
  206                 break;
  207 
  208         case 2: /* Extended Segment Address Record (HEX86) */
  209         case 4: /* Extended Linear Address Record (HEX386) */
  210                 if (record->addr || record->len != 2) {
  211                         fprintf(stderr, "Bad HEX86/HEX386 record (type %02X) at line %d\n",
  212                                 type, line);
  213                         return -EINVAL;
  214                 }
  215 
  216                 /* We shouldn't really be using the offset for HEX86 because
  217                  * the wraparound case is specified quite differently. */
  218                 offset = record->data[0] << 8 | record->data[1];
  219                 offset <<= (type == 2 ? 4 : 16);
  220                 goto next_record;
  221 
  222         case 3: /* Start Segment Address Record */
  223         case 5: /* Start Linear Address Record */
  224                 if (record->addr || record->len != 4) {
  225                         fprintf(stderr, "Bad Start Address record (type %02X) at line %d\n",
  226                                 type, line);
  227                         return -EINVAL;
  228                 }
  229 
  230                 memcpy(&data32, &record->data[0], sizeof(data32));
  231                 data32 = htonl(data32);
  232                 memcpy(&record->data[0], &data32, sizeof(data32));
  233 
  234                 /* These records contain the CS/IP or EIP where execution
  235                  * starts. If requested output this as a record. */
  236                 if (include_jump)
  237                         file_record(record);
  238                 goto next_record;
  239 
  240         default:
  241                 fprintf(stderr, "Unknown record (type %02X)\n", type);
  242                 return -EINVAL;
  243         }
  244 
  245         return 0;
  246 }
  247 
  248 static struct ihex_binrec *records;
  249 
  250 static void file_record(struct ihex_binrec *record)
  251 {
  252         struct ihex_binrec **p = &records;
  253 
  254         while ((*p) && (!sort_records || (*p)->addr < record->addr))
  255                 p = &((*p)->next);
  256 
  257         record->next = *p;
  258         *p = record;
  259 }
  260 
  261 static int output_records(int outfd)
  262 {
  263         unsigned char zeroes[6] = {0, 0, 0, 0, 0, 0};
  264         struct ihex_binrec *p = records;
  265 
  266         while (p) {
  267                 uint16_t writelen = (p->len + 9) & ~3;
  268 
  269                 p->addr = htonl(p->addr);
  270                 p->len = htons(p->len);
  271                 if (write(outfd, &p->addr, writelen) != writelen)
  272                         return 1;
  273                 p = p->next;
  274         }
  275         /* EOF record is zero length, since we don't bother to represent
  276            the type field in the binary version */
  277         if (write(outfd, zeroes, 6) != 6)
  278                 return 1;
  279         return 0;
  280 }

Cache object: 9250e885439956eb50c2815ab2bc6fee


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.