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

Sources/firmware-utils/src/mkmerakifw.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.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 
 12 #include <stdio.h>
 13 #include <stdlib.h>
 14 #include <stdbool.h>
 15 #include <string.h>
 16 #include <libgen.h>
 17 #include <getopt.h>
 18 #include <errno.h>
 19 #include <arpa/inet.h>
 20 
 21 #include "sha1.h"
 22 
 23 #define PADDING_BYTE            0xff
 24 
 25 #define HDR_LENGTH              0x00000400
 26 #define HDR_OFF_MAGIC1          0
 27 #define HDR_OFF_HDRLEN          4
 28 #define HDR_OFF_IMAGELEN        8
 29 #define HDR_OFF_CHECKSUM        12
 30 #define HDR_OFF_MAGIC2          32
 31 #define HDR_OFF_MAGIC3          36
 32 #define HDR_OFF_STATICHASH      40
 33 #define HDR_OFF_KERNEL_OFFSET   40
 34 #define HDR_OFF_RAMDISK_OFFSET  44
 35 #define HDR_OFF_FDT_OFFSET      48
 36 #define HDR_OFF_UNKNOWN_OFFSET  52
 37 
 38 struct board_info {
 39         uint32_t magic1;
 40         uint32_t magic2;
 41         uint32_t magic3;
 42         uint32_t imagelen;
 43         union {
 44                 unsigned char statichash[20];
 45                 struct {
 46                         uint32_t kernel_offset;
 47                         uint32_t ramdisk_offset;
 48                         uint32_t fdt_offset;
 49                         uint32_t unknown_offset;
 50                 } mx60;
 51         } u;
 52         char *id;
 53         char *description;
 54 };
 55 
 56 /*
 57  * Globals
 58  */
 59 static char *progname;
 60 
 61 static char *board_id;
 62 static const struct board_info *board;
 63 
 64 static const struct board_info boards[] = {
 65         {
 66                 .id             = "mr18",
 67                 .description    = "Meraki MR18 Access Point",
 68                 .magic1         = 0x8e73ed8a,
 69                 .magic2         = 0x8e73ed8a,
 70                 .imagelen       = 0x00800000,
 71                 .u.statichash   = {0xda, 0x39, 0xa3, 0xee, 0x5e,
 72                                    0x6b, 0x4b, 0x0d, 0x32, 0x55,
 73                                    0xbf, 0xef, 0x95, 0x60, 0x18,
 74                                    0x90, 0xaf, 0xd8, 0x07, 0x09},
 75         }, {
 76                 .id             = "mr24",
 77                 .description    = "Meraki MR24 Access Point",
 78                 .magic1         = 0x8e73ed8a,
 79                 .magic2         = 0x8e73ed8a,
 80                 .imagelen       = 0x00800000,
 81                 .u.statichash   = {0xff, 0xff, 0xff, 0xff, 0xff,
 82                                    0xff, 0xff, 0xff, 0xff, 0xff,
 83                                    0xff, 0xff, 0xff, 0xff, 0xff,
 84                                    0xff, 0xff, 0xff, 0xff, 0xff},
 85         }, {
 86                 .id             = "mx60",
 87                 .description    = "Meraki MX60/MX60W Security Appliance",
 88                 .magic1         = 0x8e73ed8a,
 89                 .magic2         = 0xa1f0beef, /* Enables use of load addr in statichash */
 90                 .magic3         = 0x00060001, /* This goes along with magic2 */
 91                 .imagelen       = 0x3fd00000,
 92                 /* The static hash below does the following:
 93                  * 1st Row: Kernel Offset
 94                  * 2nd Row: Ramdisk Offset
 95                  * 3rd Row: FDT Offset
 96                  * 4th Row: ? Unused/Unknown ?
 97                  * 5th Row: ? Unused/Unknown ?
 98                  */
 99                 .u.mx60         = {
100                         .kernel_offset  = 0x10000,
101                         .ramdisk_offset = 0x3FFC00,
102                         .fdt_offset     = 0x0400,
103                         .unknown_offset = 0x0400,
104                 },
105         }, {
106                 /* terminating entry */
107         }
108 };
109 
110 /*
111  * Message macros
112  */
113 #define ERR(fmt, ...) do { \
114         fflush(0); \
115         fprintf(stderr, "[%s] *** error: " fmt "\n", \
116                         progname, ## __VA_ARGS__); \
117 } while (0)
118 
119 #define ERRS(fmt, ...) do { \
120         int save = errno; \
121         fflush(0); \
122         fprintf(stderr, "[%s] *** error: " fmt "\n", \
123                         progname, ## __VA_ARGS__, strerror(save)); \
124 } while (0)
125 
126 static const struct board_info *find_board(const char *id)
127 {
128         const struct board_info *ret;
129         const struct board_info *board;
130 
131         ret = NULL;
132         for (board = boards; board->id != NULL; board++) {
133                 if (strcasecmp(id, board->id) == 0) {
134                         ret = board;
135                         break;
136                 }
137         }
138 
139         return ret;
140 }
141 
142 static void usage(int status)
143 {
144         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
145         const struct board_info *board;
146 
147         fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
148         fprintf(stream,
149 "\n"
150 "Options:\n"
151 "  -B <board>      create image for the board specified with <board>\n"
152 "  -i <file>       read kernel image from the file <file>\n"
153 "  -o <file>       write output to the file <file>\n"
154 "  -s              strip padding from the end of the image\n"
155 "  -h              show this screen\n"
156         );
157 
158         fprintf(stream, "\nBoards:\n");
159         for (board = boards; board->id != NULL; board++)
160                 fprintf(stream, "  %-16s%s\n", board->id, board->description);
161 
162         exit(status);
163 }
164 
165 void writel(unsigned char *buf, size_t offset, uint32_t value)
166 {
167         value = htonl(value);
168         memcpy(buf + offset, &value, sizeof(uint32_t));
169 }
170 
171 int main(int argc, char *argv[])
172 {
173         int ret = EXIT_FAILURE;
174         long klen;
175         size_t kspace;
176         unsigned char *kernel;
177         size_t buflen;
178         unsigned char *buf;
179         bool strip_padding = false;
180         char *ofname = NULL, *ifname = NULL;
181         FILE *out, *in;
182 
183         progname = basename(argv[0]);
184 
185         while (1) {
186                 int c;
187 
188                 c = getopt(argc, argv, "B:i:o:sh");
189                 if (c == -1)
190                         break;
191 
192                 switch (c) {
193                 case 'B':
194                         board_id = optarg;
195                         break;
196                 case 'i':
197                         ifname = optarg;
198                         break;
199                 case 'o':
200                         ofname = optarg;
201                         break;
202                 case 's':
203                         strip_padding = true;
204                         break;
205                 case 'h':
206                         usage(EXIT_SUCCESS);
207                         break;
208                 default:
209                         usage(EXIT_FAILURE);
210                         break;
211                 }
212         }
213 
214         if (board_id == NULL) {
215                 ERR("no board specified");
216                 goto err;
217         }
218 
219         board = find_board(board_id);
220         if (board == NULL) {
221                 ERR("unknown board \"%s\"", board_id);
222                 goto err;
223         }
224 
225         if (ifname == NULL) {
226                 ERR("no input file specified");
227                 goto err;
228         }
229 
230         if (ofname == NULL) {
231                 ERR("no output file specified");
232                 goto err;
233         }
234 
235         in = fopen(ifname, "r");
236         if (in == NULL) {
237                 ERRS("could not open \"%s\" for reading: %s", ifname);
238                 goto err;
239         }
240 
241         buflen = board->imagelen;
242         kspace = buflen - HDR_LENGTH;
243 
244         /* Get kernel length */
245         fseek(in, 0, SEEK_END);
246         klen = ftell(in);
247         rewind(in);
248 
249         if (klen > kspace) {
250                 ERR("file \"%s\" is too big - max size: 0x%08lX\n",
251                     ifname, kspace);
252                 goto err_close_in;
253         }
254 
255         /* If requested, resize buffer to remove padding */
256         if (strip_padding)
257                 buflen = klen + HDR_LENGTH;
258 
259         /* Allocate and initialize buffer for final image */
260         buf = malloc(buflen);
261         if (buf == NULL) {
262                 ERRS("no memory for buffer: %s\n");
263                 goto err_close_in;
264         }
265         memset(buf, PADDING_BYTE, buflen);
266 
267         /* Load kernel */
268         kernel = buf + HDR_LENGTH;
269         fread(kernel, klen, 1, in);
270 
271         /* Write magic values */
272         writel(buf, HDR_OFF_MAGIC1, board->magic1);
273         writel(buf, HDR_OFF_MAGIC2, board->magic2);
274         writel(buf, HDR_OFF_MAGIC3, board->magic3);
275 
276         /* Write header and image length */
277         writel(buf, HDR_OFF_HDRLEN, HDR_LENGTH);
278         writel(buf, HDR_OFF_IMAGELEN, klen);
279 
280         /* Write checksum and static hash */
281         sha1_csum(kernel, klen, buf + HDR_OFF_CHECKSUM);
282 
283         switch (board->magic2) {
284         case 0xa1f0beef:
285                 writel(buf, HDR_OFF_KERNEL_OFFSET, board->u.mx60.kernel_offset);
286                 writel(buf, HDR_OFF_RAMDISK_OFFSET, board->u.mx60.ramdisk_offset);
287                 writel(buf, HDR_OFF_FDT_OFFSET, board->u.mx60.fdt_offset),
288                 writel(buf, HDR_OFF_UNKNOWN_OFFSET, board->u.mx60.unknown_offset);
289                 break;
290 
291         case 0x8e73ed8a:
292                 memcpy(buf + HDR_OFF_STATICHASH, board->u.statichash, 20);
293                 break;
294         }
295 
296         /* Save finished image */
297         out = fopen(ofname, "w");
298         if (out == NULL) {
299                 ERRS("could not open \"%s\" for writing: %s", ofname);
300                 goto err_free;
301         }
302         fwrite(buf, buflen, 1, out);
303 
304         ret = EXIT_SUCCESS;
305 
306         fclose(out);
307 
308 err_free:
309         free(buf);
310 
311 err_close_in:
312         fclose(in);
313 
314 err:
315         return ret;
316 }
317 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt