base-files: don't overwrite model name set by target
[oweals/openwrt.git] / tools / firmware-utils / src / mkmerakifw-old.c
1 /*
2  * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
3  * Copyright (C) 2016 Christian Lamparter <chunkeey@googlemail.com>
4  *
5  * The format of the header this tool generates was first documented by
6  * Chris Blake <chrisrblake93 (at) gmail.com> in a shell script of the
7  * same purpose. I have created this reimplementation at his request. The
8  * original script can be found at:
9  * <https://github.com/riptidewave93/meraki-partbuilder>
10  *
11  * Support for the old header format, which is used by the Cisco Z1 AP
12  * has been reverse engineered from the nandloader's nand_load_bk function.
13  * The original code is part of Cisco's GPL code and can be found at:
14  * <https://github.com/riptidewave93/meraki-linux>
15  *
16  * This program is free software; you can redistribute it and/or modify it
17  * under the terms of the GNU General Public License version 2 as published
18  * by the Free Software Foundation.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <libgen.h>
27 #include <endian.h>
28 #include <getopt.h>
29 #include <errno.h>
30 #include <arpa/inet.h>
31
32 #define PADDING_BYTE            0xff
33
34 #define HDR_LENGTH              0x00000020
35 #define HDR_OFF_MAGIC1  0
36 #define HDR_OFF_LOAD_ADDR       4
37 #define HDR_OFF_IMAGELEN        8
38 #define HDR_OFF_ENTRY   12
39 #define HDR_OFF_CHECKSUM        16
40 #define HDR_OFF_FILLER0 20
41 #define HDR_OFF_FILLER1 24
42 #define HDR_OFF_FILLER2 28
43
44 struct board_info {
45         char *id;
46         char *description;
47         uint32_t magic;
48         uint32_t imagelen;
49         uint32_t load_addr;
50         uint32_t entry;
51 };
52
53 /*
54  * Globals
55  */
56 static char *progname;
57 static bool strip_padding;
58
59 static char *board_id;
60 static const struct board_info *board;
61
62 static const struct board_info boards[] = {
63         {
64                 .id             = "z1",
65                 .description    = "Meraki Z1 Access Point",
66                 .magic          = 0x4d495053,
67                 .imagelen       = 0x007e0000,
68                 .load_addr      = 0x80060000,
69                 .entry          = 0x80060000
70         }, {
71                 /* terminating entry */
72         }
73 };
74
75 /*
76  * Message macros
77  */
78 #define ERR(fmt, ...) do { \
79         fflush(0); \
80         fprintf(stderr, "[%s] *** error: " fmt "\n", \
81                         progname, ## __VA_ARGS__); \
82 } while (0)
83
84 #define ERRS(fmt, ...) do { \
85         int save = errno; \
86         fflush(0); \
87         fprintf(stderr, "[%s] *** error: " fmt "\n", \
88                         progname, ## __VA_ARGS__, strerror(save)); \
89 } while (0)
90
91 static const struct board_info *find_board(const char *id)
92 {
93         const struct board_info *ret;
94         const struct board_info *board;
95
96         ret = NULL;
97         for (board = boards; board->id != NULL; board++) {
98                 if (strcasecmp(id, board->id) == 0) {
99                         ret = board;
100                         break;
101                 }
102         }
103
104         return ret;
105 }
106
107 static void usage(int status)
108 {
109         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
110         const struct board_info *board;
111
112         fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
113         fprintf(stream,
114 "\n"
115 "Options:\n"
116 "  -B <board>      create image for the board specified with <board>\n"
117 "  -i <file>       read kernel image from the file <file>\n"
118 "  -o <file>       write output to the file <file>\n"
119 "  -s              strip padding from the end of the image\n"
120 "  -h              show this screen\n"
121         );
122
123         fprintf(stream, "\nBoards:\n");
124         for (board = boards; board->id != NULL; board++)
125                 fprintf(stream, "  %-16s%s\n", board->id, board->description);
126
127         exit(status);
128 }
129
130 static void writel(unsigned char *buf, size_t offset, uint32_t value)
131 {
132         value = htonl(value);
133         memcpy(buf + offset, &value, sizeof(uint32_t));
134 }
135
136 static const uint32_t crc32_table[] = {
137         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
138         0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
139         0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
140         0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
141         0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
142         0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
143         0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
144         0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
145         0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
146         0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
147         0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
148         0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
149         0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
150         0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
151         0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
152         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
153         0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
154         0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
155         0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
156         0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
157         0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
158         0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
159         0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
160         0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
161         0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
162         0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
163         0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
164         0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
165         0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
166         0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
167         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
168         0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
169         0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
170         0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
171         0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
172         0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
173         0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
174         0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
175         0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
176         0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
177         0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
178         0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
179         0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
180         0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
181         0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
182         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
183         0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
184         0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
185         0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
186         0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
187         0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
188         0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
189         0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
190         0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
191         0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
192         0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
193         0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
194         0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
195         0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
196         0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
197         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
198         0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
199         0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
200         0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
201 };
202
203 static inline uint32_t crc32_accumulate_8(const uint32_t crc, const uint8_t ch)
204 {
205         return crc32_table[(crc ^ ch) & 0xff] ^ (crc >> 8);
206 }
207
208 static void crc32_csum(uint8_t *buf, const size_t len)
209 {
210         uint32_t crc;
211         size_t i;
212
213         crc = ~0;
214         for (i = 0; i < len; i += 4) {
215                 crc = crc32_accumulate_8(crc, buf[i + 3]);
216                 crc = crc32_accumulate_8(crc, buf[i + 2]);
217                 crc = crc32_accumulate_8(crc, buf[i + 1]);
218                 crc = crc32_accumulate_8(crc, buf[i]);
219         }
220         crc = ~crc;
221
222         writel(buf, HDR_OFF_CHECKSUM, crc);
223 }
224
225
226 static int meraki_build_hdr(const struct board_info *board, const size_t klen,
227                             FILE *out, FILE *in)
228 {
229         unsigned char *kernel;
230         unsigned char *buf;
231         size_t buflen;
232         size_t kspace;
233
234         size_t rc;
235         buflen = board->imagelen;
236         kspace = buflen - HDR_LENGTH;
237
238         if (klen > kspace) {
239                 ERR("kernel file is too big - max size: 0x%08lX\n", kspace);
240                 return EXIT_FAILURE;
241         }
242
243         /* If requested, resize buffer to remove padding */
244         if (strip_padding)
245                 buflen = klen + HDR_LENGTH;
246
247         /* Allocate and initialize buffer for final image */
248         buf = malloc(buflen);
249         if (buf == NULL) {
250                 ERRS("no memory for buffer: %s\n");
251                 return EXIT_FAILURE;
252         }
253         memset(buf, PADDING_BYTE, buflen);
254
255         /* Load kernel */
256         kernel = buf + HDR_LENGTH;
257         fread(kernel, klen, 1, in);
258
259         /* Write magic values and filler */
260         writel(buf, HDR_OFF_MAGIC1, board->magic);
261         writel(buf, HDR_OFF_FILLER0, 0);
262         writel(buf, HDR_OFF_FILLER1, 0);
263         writel(buf, HDR_OFF_FILLER2, 0);
264
265         /* Write load and kernel entry point address */
266         writel(buf, HDR_OFF_LOAD_ADDR, board->load_addr);
267         writel(buf, HDR_OFF_ENTRY, board->entry);
268
269         /* Write header and image length */
270         writel(buf, HDR_OFF_IMAGELEN, klen);
271
272         /* this gets replaced later, after the checksum has been calculated */
273         writel(buf, HDR_OFF_CHECKSUM, 0);
274
275         /* Write checksum */
276         crc32_csum(buf, klen + HDR_LENGTH);
277
278         rc = fwrite(buf, buflen, 1, out);
279
280         free(buf);
281
282         return rc == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
283 }
284
285 int main(int argc, char *argv[])
286 {
287         int ret = EXIT_FAILURE;
288         char *ofname = NULL, *ifname = NULL;
289         FILE *out, *in;
290         size_t klen;
291
292         progname = basename(argv[0]);
293
294         while (1) {
295                 int c;
296
297                 c = getopt(argc, argv, "B:i:o:sh");
298                 if (c == -1)
299                         break;
300
301                 switch (c) {
302                 case 'B':
303                         board_id = optarg;
304                         break;
305                 case 'i':
306                         ifname = optarg;
307                         break;
308                 case 'o':
309                         ofname = optarg;
310                         break;
311                 case 's':
312                         strip_padding = true;
313                         break;
314                 case 'h':
315                         usage(EXIT_SUCCESS);
316                         break;
317                 default:
318                         usage(EXIT_FAILURE);
319                         break;
320                 }
321         }
322
323         if (board_id == NULL) {
324                 ERR("no board specified");
325                 goto err;
326         }
327
328         board = find_board(board_id);
329         if (board == NULL) {
330                 ERR("unknown board \"%s\"", board_id);
331                 goto err;
332         }
333
334         if (ifname == NULL) {
335                 ERR("no input file specified");
336                 goto err;
337         }
338
339         if (ofname == NULL) {
340                 ERR("no output file specified");
341                 goto err;
342         }
343
344         in = fopen(ifname, "r");
345         if (in == NULL) {
346                 ERRS("could not open \"%s\" for reading: %s", ifname);
347                 goto err;
348         }
349
350         /* Get kernel length */
351         fseek(in, 0, SEEK_END);
352         klen = ftell(in);
353         rewind(in);
354
355         out = fopen(ofname, "w");
356         if (out == NULL) {
357                 ERRS("could not open \"%s\" for writing: %s", ofname);
358                 goto err_close_in;
359         }
360
361         ret = meraki_build_hdr(board, klen, out, in);
362         fclose(out);
363
364 err_close_in:
365         fclose(in);
366
367 err:
368         return ret;
369 }