ar7: add eva image generation (thanks Axel Gembe)
[15.05/openwrt.git] / tools / firmware-utils / src / lzma2eva.c
1 /*
2     lzma2eva - convert lzma-compressed file to AVM EVA bootloader format
3     Copyright (C) 2007  Enrik Berkhan <Enrik.Berkhan@inka.de>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18 */
19
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <zlib.h> /* crc32 */
24
25 #define checksum_add32(csum, data) \
26   csum += ((uint8_t *)&data)[0]; \
27   csum += ((uint8_t *)&data)[1]; \
28   csum += ((uint8_t *)&data)[2]; \
29   csum += ((uint8_t *)&data)[3];
30
31 void
32 usage(void)
33 {
34   fprintf(stderr, "usage: lzma2eva <loadadddr> <entry> <lzmafile> <evafile>\n");
35   exit(1);
36 }
37
38 void
39 pexit(const char *msg)
40 {
41   perror(msg);
42   exit(1);
43 }
44
45 int
46 main(int argc, char *argv[])
47 {
48
49   const char *infile, *outfile;
50   FILE *in, *out;
51   static const uint8_t buf[4096];
52   size_t elems;
53
54   uint8_t properties;
55   uint32_t dictsize;
56   uint64_t datasize;
57
58   uint32_t magic = 0xfeed1281L;
59   uint32_t reclength = 0;
60   fpos_t reclengthpos;
61   uint32_t loadaddress = 0;
62   uint32_t type = 0x075a0201L; /* might be 7Z 2.1? */
63   uint32_t checksum = 0;
64
65   uint32_t compsize = 0;
66   fpos_t compsizepos;
67   uint32_t datasize32 = 0;
68   uint32_t datacrc32 = crc32(0, 0, 0);
69
70   uint32_t zero = 0;
71   uint32_t entry = 0;
72
73   if (argc != 5)
74     usage();
75
76   /* "parse" command line */
77   loadaddress = strtoul(argv[1], 0, 0);
78   entry = strtoul(argv[2], 0, 0);
79   infile = argv[3];
80   outfile = argv[4];
81
82   in = fopen(infile, "rb");
83   if (!in)
84     pexit("fopen");
85   out = fopen(outfile, "w+b");
86   if (!out)
87     pexit("fopen");
88
89   /* read LZMA header */
90   if (1 != fread(&properties, sizeof properties, 1, in))
91     pexit("fread");
92   if (1 != fread(&dictsize, sizeof dictsize, 1, in))
93     pexit("fread");
94   if (1 != fread(&datasize, sizeof datasize, 1, in))
95     pexit("fread");
96
97   /* write EVA header */
98   if (1 != fwrite(&magic, sizeof magic, 1, out))
99     pexit("fwrite");
100   if (fgetpos(out, &reclengthpos))
101     pexit("fgetpos");
102   if (1 != fwrite(&reclength, sizeof reclength, 1, out))
103     pexit("fwrite");
104   if (1 != fwrite(&loadaddress, sizeof loadaddress, 1, out))
105     pexit("fwrite");
106   if (1 != fwrite(&type, sizeof type, 1, out))
107     pexit("fwrite");
108
109   /* write EVA LZMA header */
110   if (fgetpos(out, &compsizepos))
111     pexit("fgetpos");
112   if (1 != fwrite(&compsize, sizeof compsize, 1, out))
113     pexit("fwrite");
114   /* XXX check length */
115   datasize32 = (uint32_t)datasize;
116   if (1 != fwrite(&datasize32, sizeof datasize32, 1, out))
117     pexit("fwrite");
118   if (1 != fwrite(&datacrc32, sizeof datacrc32, 1, out))
119     pexit("fwrite");
120
121   /* write modified LZMA header */
122   if (1 != fwrite(&properties, sizeof properties, 1, out))
123     pexit("fwrite");
124   if (1 != fwrite(&dictsize, sizeof dictsize, 1, out))
125     pexit("fwrite");
126   if (1 != fwrite(&zero, 3, 1, out))
127     pexit("fwrite");
128
129   /* copy compressed data, calculate crc32 */
130   while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, in))) {
131     compsize += elems;
132     if (elems != fwrite(&buf, sizeof buf[0], elems, out))
133       pexit("fwrite");
134     datacrc32 = crc32(datacrc32, buf, elems);
135   }
136   if (ferror(in))
137     pexit("fread");
138   fclose(in);
139
140   /* re-write record length */
141   reclength = compsize + 24;
142   if (fsetpos(out, &reclengthpos))
143     pexit("fsetpos");
144   if (1 != fwrite(&reclength, sizeof reclength, 1, out))
145     pexit("fwrite");
146
147   /* re-write EVA LZMA header including size and data crc */
148   if (fsetpos(out, &compsizepos))
149     pexit("fsetpos");
150   if (1 != fwrite(&compsize, sizeof compsize, 1, out))
151     pexit("fwrite");
152   if (1 != fwrite(&datasize32, sizeof datasize32, 1, out))
153     pexit("fwrite");
154   if (1 != fwrite(&datacrc32, sizeof datacrc32, 1, out))
155     pexit("fwrite");
156
157   /* calculate record checksum */
158   checksum += reclength;
159   checksum += loadaddress;
160   checksum_add32(checksum, type);
161   checksum_add32(checksum, compsize);
162   checksum_add32(checksum, datasize32);
163   checksum_add32(checksum, datacrc32);
164   if (fseek(out, 0, SEEK_CUR))
165     pexit("fseek");
166   while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, out))) {
167     size_t i;
168     for (i = 0; i < elems; ++i)
169       checksum += buf[i];
170   }
171   if (ferror(out))
172     pexit("fread");
173   if (fseek(out, 0, SEEK_CUR))
174     pexit("fseek");
175
176   checksum = ~checksum + 1;
177   if (1 != fwrite(&checksum, sizeof checksum, 1, out))
178     pexit("fwrite");
179
180   /* write entry record */
181   if (1 != fwrite(&zero, sizeof zero, 1, out))
182     pexit("fwrite");
183   if (1 != fwrite(&entry, sizeof entry, 1, out))
184     pexit("fwrite");
185
186   if (fclose(out))
187     pexit("fclose");
188
189   return 0;
190 }